Can I create more function in ApiController? - asp.net-mvc-4

I am new in web api and I am creating a demo with default Web API, I see that ValuesController has default 4 functions Get,Post,Put and Delete. I see that the ValuesController impleament 4 function to ApiController which can not modify. So, Can I write some more functions like search item by price or model ? If can, what url on browser to run debug for new function ?
thankyou

It sounds like you need to add new actions to your controller. You will need to modify (or add to) your Routes in your WebApiConfig.cs file to include action mapping.
For example, let's say you update your Controller with the additional functions GetTestString1 and GetTestString2:
public class TestController : ApiController
{
public String GetTestString1(int id)
{
return "Test String 1 for " + id;
}
public String GetTestString2(int id)
{
return "Test String 2 for " + id;
}
}
To perform the routing to these new functions you need to add the following to the WebApiConfig.cs file in the App_Start folder:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// This mapping entry may already exist for you. Leave it alone
// so your existing default functions continue to work properly.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Add this to route your new functions:
config.Routes.MapHttpRoute(
name: "TestStringApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
The above routeTemplate "api/{controller}/{action}/{id}" is how the request URL will be routed to your controller and actions (functions). The {controller} part of the URL will route to your TestController class. The {action} part of the URL is the additional function you asked about and will be mapped to GetTestString1 or GetTestString2 depending on what you request in your URL.
When you open your browser to this address,
http://localhost:60303/api/Test/GetTestString1/100
the route you registered in the WebApiConfig.cs will map the url to your Testcontroller's GetTestString1 action (function) with 100 as the input parameter and will return "Test String 1 for 100" to the browser.
You can call your Testcontroller's GetTestString2 action (function) like this
http://localhost:60303/api/Test/GetTestString2/101
and "Test String 2 for 101" will be returned to the browser.
You can learn more about the how the default functions work (get, post delete) and more about actions and parameters here:
http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
Here are some related discussions similar to this topic:
Routing with Multiple Parameters using ASP.NET MVC
Routing with action after id parameter in Web API

Related

Web API One action works while a nearly identical one doesn't?

Error Message
{
"Message": "No HTTP resource was found that matches the request URI 'https://localhost:44390/api/UserRoutes?effectiveDate=3/29/2019'.",
"MessageDetail": "No type was found that matches the controller named 'UserRoutes'."
}
Working Action
public class AdvanceOrderApiController : BaseApiController
{
[HttpGet, Route("api/AdvanceOrders")]
public AdvanceOrdersResult GetAdvanceOrdersForRouteDate(string route, DateTime effectiveDate)
{
...
}
}
// JavaScript Usage: route="0100" and effectiveDate="03/29/2019".
API.SendRequest("/api/AdvanceOrders", "GET", { route: route, effectiveDate: effectiveDate }, success, failure);
Not Working Action
public class UserApiController : BaseApiController
{
[HttpGet, Route("api/UserRoutes")]
public IEnumerable<string> GetUserRoutes(DateTime effectiveDate)
{
...
}
}
// JavaScript Usage: effectiveDate="03/29/2019"
API.SendRequest("/api/UserRoutes", "GET", { effectiveDate: effectiveDate }, success, failure);
WebApiConfig
Not sure that it's relevant since I'm just declaring the route for each action, but...
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
...
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
API.SendRequest
This function is just a wrapper around jQuery's $.ajax function, nothing fancy. If the code is necessary I'll present it, but it works for all my other API calls so I can't imagine it would be the source of the problem.
These actions are nearly identical, why does one work and the other doesn't?
Passing the date in as Igor said in the comments presented an error message that revealed that I had an Api controller in my Permissions area that had a route also named api/UserRoutes.
Once I changed the name of the route the problem resolved.
I just wish it could have just told me this error message from the start.

Unable to call WebApi 2 method

I've added a webapi 2 controller to my project, inside api > LoginAPi as shown here:
Inside LoginApi I have the following:
[RoutePrefix("api/LoginApi")]
public class LoginApi : ApiController
{
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
}
Inside my global.asax file I have:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
Inside App_Start I have the following:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I then put a break point inside the Get method within LoginAPI and run the project and type the following into the URL:
http://localhost:37495/api/LoginApi/4
But I get :
No HTTP resource was found that matches the request URI 'http://localhost:37495/api/LoginApi/4'.
So I thought OK let me specify the method name as so
http://localhost:37495/api/LoginApi/Get/4
This returns:
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
Now I've been looking at this for a while so maybe I've missed something obvious, but if someone can please tell me what I'm doing wrong I'd very much appreciate it.
The routeTemplate you have set up would work for convention-based routing except for the fact that Web API adds the string "Controller" when searching for the controller class (as per this article). You therefore need to rename your controller class LoginApiController in order for the convention-based routing to work.
For attribute-based routing, the addition of the RoutePrefix attribute should be combined with a Route attribute on your action. Try adding the following to your Get method in your controller:
[HttpGet]
[Route("{id}")]
And then navigate to http://localhost:37495/api/LoginApi/4.

Visual Studio MVC4 Auto Url Routing for All Url's

Hello everyone I am working with VS13 MVC4 in localhost, for url routing I want VS will work for all url's automatically as www.sitename.com/about-us but now it is getting underscore (_) not dash (-) how to make a change and get hyphen(-) before every new word in url
Here is the answer I also add it to my question for everyone can see:
public class HyphenatedRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["controller"] = requestContext.RouteData.Values["controller"].ToString().Replace("-", "_");
requestContext.RouteData.Values["action"] = requestContext.RouteData.Values["action"].ToString().Replace("-", "_");
return base.GetHttpHandler(requestContext);
}
}
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
new Route("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Default", action = "Index", id = "" }),
new HyphenatedRouteHandler())
);
}
}
Thanks everyone.
If you want pretty url in asp.net mvc then you should go by registering new route for your controller.
from the application directory open RouteConfig.cs in the App_Start directory.
And in the RegisterRoutes method of RouteConfig class register a new route like this-
routes.MapRoute(
name: "AboutUs",
url: "sitename/about-us",
defaults: new { controller = "About_Us", action = "Index" }
);
The _ will prob be automatically converted to a - in the routing. The other way is to set up the routing yourself

Web api routing methods with different parameter names

This question could have been answered hundred times, but I couldnt find a proper resource. In a WebApi project (default project provided by VS) I have the ValuesController as below.
public string Get(int id)
{
return "value";
}
[HttpGet]
public string FindByName(string name)
{
return name;
}
[HttpGet]
public string FindById(int id)
{
return id.ToString();
}
In the WebApiConfig.cs, I have following route mapping.
config.Routes.MapHttpRoute(
name: "actionApiById",
routeTemplate: "api/{controller}/{action}/{Id}",
defaults: new { action = "FindById", Id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "actionApi",
routeTemplate: "api/{controller}/{action}/{name}",
defaults: new { name = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Now only the FindById() action is working when i try in the browser. Why does the rest of api calls return "No HTTP resource was found that matches the request"
How can I get all three methods working? without using AttributeRouting. Am I lack of basic concepts of web api? ( i think yes)
AS We all know REST is resource based and this identify the resource with the URL, so that not more than one method with same parameter will be allowed in the REST service but there is work around in MVC 5 Web Api method level routing.
Here is the example you can do that:
[HttpGet]
[Route("api/search/FindByName/{name}")]
FindByName(string name)
{
}
[HttpGet]
[Route("api/search/FindById/{name}")]
FindById(int searchId)
Note:"search" is the controller name.
Please let know if need more clarification.
In general you don't want to have a route per action like your sample suggests. As your app grows this will get quickly out of hand.
Also consider building your url space in a way that will look just RESTfull
So methods will be GetById, GetByName, and then pass the parameters in the query string to match the right action (BTW not sure what the difference in your case is between GetById and FindById if they are not really different consider just keeping one of them around).
You can stick with the default route and your request will look like:
/api/controller/345 or /api/controller?name=UserName or /api/controller?SearchId=345 (assuming search was indeed a different behavior)
Then the method signatures:
Get(int id)
{
}
[HttpGet]
FindByName(string name)
{
}
[HttpGet]
FindById(int searchId)
{
}
Your actionApiById Route also matches the actionApi route, As your id is integer try using constraint like this.
config.Routes.MapHttpRoute(
name: "actionApiById",
routeTemplate: "api/{controller}/{action}/{Id}",
defaults: new { action = "FindById", Id = RouteParameter.Optional }
constraints: new {Id = #"\d+" }
);

How to create ASP.NET Web API Url?

In ASP.NET MVC, we have #Url.Action for actions. Is there something similar like #Url.Api which would route to /api/controller?
The ApiController has a property called Url which is of type System.Web.Http.Routing.UrlHelper which allows you to construct urls for api controllers.
Example:
public class ValuesController : ApiController
{
// GET /api/values
public IEnumerable<string> Get()
{
// returns /api/values/123
string url = Url.Route("DefaultApi", new { controller = "values", id = "123" });
return new string[] { "value1", "value2" };
}
// GET /api/values/5
public string Get(int id)
{
return "value";
}
...
}
This UrlHelper doesn't exist neither in your views nor in the standard controllers.
UPDATE:
And in order to do routing outside of an ApiController you could do the following:
public class HomeController : Controller
{
public ActionResult Index()
{
string url = Url.RouteUrl(
"DefaultApi",
new { httproute = "", controller = "values", id = "123" }
);
return View();
}
}
or inside a view:
<script type="text/javascript">
var url = '#Url.RouteUrl("DefaultApi", new { httproute = "", controller = "values", id = "123" })';
$.ajax({
url: url,
type: 'GET',
success: function(result) {
// ...
}
});
</script>
Notice the httproute = "" route token which is important.
Obviously this assumes that your Api route is called DefaultApi in your RegisterRoutes method in Global.asax:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
It works with the simpler form of Url.Action thus you don't have to reference any Routing names:
Url.Action("ActionName", "ControllerName", new { httproute = "DefaultApi" })
You might want to add an area = "" if the URL is needed within an Area. (Api controllers are outside of Areas by default.) I'm using MVC 4.
Want to be able to generate links in a typesafe manner, without hardcoded strings (controller names)?
There's a nuget for that! (and it's written by Mark Seeman)
https://github.com/ploeh/Hyprlinkr
Works like this:
Routes, as usual:
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
Get an URL:
var linker = new RouteLinker(request);
var uri = linker.GetUri<FooController>(r => r.GetById(1337));
Result:
http://localhost/api/foo/1337
Here is the KISS method for answering the question:
If this is the code that you would use to create a MVC controller URL
#Url.Action("Edit", "MyController")
In order to get a URL for the API version of the controller (assuming you use the same controller name) you can use
#Url.Action("Edit", "api/MyController")
All the Url.Action method is doing is appending the root path of the application, with the controller name, followed by the action name (unless it is "Index" in which case it is not appended. if the route values object has an id property the value is also appended to the URL.