Action method not showing in Web API, why? - c#

I have Web API, I have written action method. but it's not correctly visible when I run the application. I cannot see SendPushNotification in the attached image.
Controller Code:
[RoutePrefix("api/OTP")]
public class OTPController : ApiController
{
public IHttpActionResult Get(int id)
{
return Ok("value");
}
[HttpGet]
public IHttpActionResult SendPushNotification(string userId, string factorId, string domain)
{
var response = _oTPRepository.SendPushNotification(userId, factorId, domain);
return Ok(response);
}

add a Route over your method, something like this:
[HttpGet]
[Route("SendPushNotification")]
public IHttpActionResult SendPushNotification(string userId, string factorId, string domain)
{
var response = _oTPRepository.SendPushNotification(userId, factorId, domain);
return Ok(response);
}
This will combine with the RoutePrefix from your controller and give you what you want.
You can call it whatever you want as well, whatever makes sense for your API.

in mentioned image second method is that for which you are actually looking for.
default routing for action methods is api/{controller_name}.
if you want to access that method as your given name you have set routing attribute above that action method.
like [Routing("api/OTP/SendPushNotification")]

Related

Is there any way to get full Url to other controller method from code?

I have Asp.Net Core web application. With following controller
[Produces("application/json")]
[Route("api/[controller]")]
public class TestController
{
[HttpGet]
[Route("firstroute")]
public async Task<IActionResult> FirstMethod()
{
...Some code...
}
[HttpGet]
[Route("secondroute")]
public async Task<IActionResult> SecondMethod()
{
...
SomeMethod(redirectLink)
...
}
}
What I need is to get fully assembled redirectLink to FirstMethod (it will probably be similar to this: "http://localhost/api/test/firstroute").
I need not RedirectToAction, but exact Url as string.
Didn't manage to find any suitable methods in this.Url or Microsoft.AspNetCore.Http.Extensions.
this.Request.GetDisplayUrl() returns result in appropriate format, but only for the called method.
you can use data from HttpContext.Request like bellow
var Url = string.Format("{0}://{1}{2}", HttpContext.Request.Scheme,HttpContext.Request.Host,"/api/firstroute");
and rediret by
return Redirect(Url);

asp.net core Api - insert new row in database

I'm trying to create an address object in a database through an asp.net core api. I'm using Postman to invoke the method.
Class:
namespace LC.Tools.API.Controllers {
[Route("api/[controller]")]
public class MailerController : Controller
{
Data.LCToolsDbContext _context;
public MailerController(Data.LCToolsDbContext context)
{
_context = context;
}
[HttpPost]
public async Task<IActionResult> CreateAddress(int client, string name, string email)
{
Address adr = new Address() { ClientId = client, Name = name, Email = email };
_context.MailerAddresses.Add(adr);
await _context.SaveChangesAsync();
return Ok(adr);
}
} }
URL (using POST):
http://localhost:50444/api/mailer/createAddress?client=1&name=test&email=mail#mail.no
I also have a break point in the method, but it never hits. I don't get any error message, it just doesn't do anything.
You can see #Rick van den Bosch's comment but still you would like to specify the route with action. use this
[Route("api/[controller]/[action]")]
See #Ayvaras' comment. Since you're building a Web API controller, you don't have to specify the action name in your URL. The HttpPost points all POST actions to the mailer controller towards the CreateAddress method.
Your POST URL should be:
http://localhost:50444/api/mailer?client=1&name=test&email=mail#mail.no
Problem solved! Thanks Ayvaras,
[Route("api/[controller]/[action]")]
did the trick. Now that the method is found I can look into how to pass an object instead of using querystring
You are not using POST correctly.
If you use POST you should not be sending parameters through the query string, you should use the request body. Even though, if you still have to send them via query string you should use the FromQuery attribute in your action parameters.
[HttpPost]
public async Task<IActionResult> CreateAddress([FromQuery] int client, [FromQuery] string name, [FromQuery] string email)
{
Address adr = new Address() { ClientId = client, Name = name, Email = email };
_context.MailerAddresses.Add(adr);
await _context.SaveChangesAsync();
return Ok(adr);
}
Edit: Use [Route("api/[controller]/[action]")] to append the action name in your action route.
Instead of changing the controllers routing scheme, it's also possible to specify the endpoint name by doing the following
[HttpPost("createAddress")]
public async Task<IActionResult> CreateAddress(int client, string name, string email)
{
[...]
}

How to call three get methods in one controller?

Hi I am developing webapi application and I have three GET methods in one controller. I am able to call 2 methods but third one I am not able to call.
Below are my methods I am able to call.
[HttpGet]
[Route("me")]
public HttpResponseMessage me()
{
return Request.CreateResponse(HttpStatusCode.OK, "Get me");
}
URL:http://localhost:22045/api/user/me
[HttpGet]
public HttpResponseMessage getUser(int id)
{
return Request.CreateResponse(HttpStatusCode.OK, "Get user");
}
URL: http://localhost:22045/api/user/1
I am not able to call below one.
[Route("user/{role}")]
public HttpResponseMessage Get(string role)
{
return Request.CreateResponse(HttpStatusCode.OK, "Get me on role");
}
I want to call it like
http://localhost:22045/api/user/OptionalRoleParameter
May I get some help here? Any help would be appreciated.
Optional route parameter as string
[Route("user/{role?}")]
public HttpResponseMessage Get(string role)
{
return Request.CreateResponse(HttpStatusCode.OK, "Get me on role");
}
You can't have string as an optional parameter because it's not supported as a nullable constraint in Web API, see this for more info, Route Constraints in Web API
Using attribute routes with route constraints should help differentiate the routes enough to avoid clashes
First ensure that attribute routing is enabled.
config.MapHttpAttributeRoutes();
Then make sure that the controller has the necessary attribute
[RoutePrefix("api/user")]
public class UsersController : ApiController {
//GET api/user/me
[HttpGet]
[Route("me")]
public HttpResponseMessage me() {
return Request.CreateResponse(HttpStatusCode.OK, "Get me");
}
//GET api/user/1
[HttpGet]
[Route("{id:int")] // NOTE the parameter constraint
public HttpResponseMessage getUser(int id) {
return Request.CreateResponse(HttpStatusCode.OK, "Get user");
}
//GET api/user
//GET api/user/OptionalRoleHere
[HttpGet]
[Route("{role?}")] //NOTE the question mark used to identify optional parameter
public HttpResponseMessage Get(string role = null) {
return Request.CreateResponse(HttpStatusCode.OK, "Get me on role");
}
}
Source: Attribute Routing in ASP.NET Web API 2 : Route Constraints

Web API 2 - Method now allowed(405) for PUT

I am stuck with Web API 2 controller, from which I call PUT method and it gives me an error that method isn't allowed. I added lines of code in Web.config that prevent WebDAV to block methods. I tried everything but it is not working. It is probably problem with my PUT method in a controller.
Here is my controller code:
public IHttpActionResult Put(int id, [FromBody]ArticleModel model) {
var article = _articleService.UpdateArticle(model);
return Ok<ArticleModel>(article);
}
This is a code from where I call put :
response = await client.PutAsJsonAsync("api/article/2", articleModel);
before this code I defined client as http and added needed properties, and called other controller methods (GET, POST, DELETE) , they all work. This is from Windows Form app, and I am also calling from Postman but still the same error.
Add [HttpPut] , [RoutePrefix("api/yourcontroller")] and [Route("put")] attribute to your controller method
Example:
[RoutePrefix("api/yourcontroller")]
public class YourController
{
[HttpPut]
[Route("{id}/put")]
public IHttpActionResult Put(int id, [FromBody]ArticleModel model) {
var article = _articleService.UpdateArticle(model);
return Ok<ArticleModel>(article);
}
}
EDIT 1
public class YourController
{
[HttpPut]
[Route("api/article/{id}/put")]
public async Task<HttpResponseMessage> Put(int id, [FromBody]ArticleModel model) {
var article = _articleService.UpdateArticle(model);
return Ok<ArticleModel>(article);
}
}
From your HttpRequest call It seems what is expected is a HttpResponseMessage So changed the return type to async Task<HttpResponseMessage>
Code for making HttpRequest:
response = await client.PutAsJsonAsync("api/article/2/put", articleModel);
Add the [System.Web.Http.HttpPut] attribute to your method.

How to have a Route which points to two different controller end points which accepts different arguments in WEB Api 2

How to have a Route which points to two different controller end points which accepts different arguments in WEB Api 2
I have two different end points declared in controller and as for the REST perspective I have to use the alpha/{aplhaid}/beta format for both the end points ,
[Authorize]
[HttpPost]
[Route("alpha/{aplhaid}/beta")]
public async Task<HttpResponseMessage> CreateAlpha(Beta beta, string projectId, [FromHeader] RevisionHeaderModel revision)
[Authorize]
[HttpPost]
[Route("alpha/{aplhaid}/beta")]
public async Task<HttpResponseMessage> CreateAlpha(List<Beta> betas, string projectId, [FromHeader] RevisionHeaderModel revision)
Is it possible to use the same router with different parameters which points to 2 different end points in Web API 2?
If you really need to have the same route and the same ActionName, you could do it with an IHttpActionSelector.
public class CustomActionSelector : ApiControllerActionSelector, IHttpActionSelector
{
public new HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
var context = HttpContext.Current;
// Read the content. Probably a better way of doing it?
var stream = new StreamReader(context.Request.InputStream);
var input = stream.ReadToEnd();
var array = new JavaScriptSerializer().Deserialize<List<string>>(input);
if (array != null)
{
// It's an array
//TODO: Choose action.
}
else
{
// It's not an array
//TODO: Choose action.
}
// Default.
var action = base.SelectAction(controllerContext);
return action;
}
public override ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
{
var lookup = base.GetActionMapping(controllerDescriptor);
return lookup;
}
}
In your WebApiConfig:
config.Services.Replace(
typeof(IHttpActionSelector),
new CustomActionSelector());
Example for your an Controller:
public class FooController: ApiController
{
[HttpPost]
public string Post(string id)
{
return "String";
}
[HttpPost]
public string Post(List<string> id)
{
return "some list";
}
}
The solution has some big downsides, if you ask me. First of, you should look for a solution for using this CustomActionSelector only when needed. Not for all controllers as it will create an overhead for each request.
I think you should reconsider why you really need two have to identical routes. I think readability will be suffering if the same route accepts different arguments. But that's just my opinion.
I would use different routes instead.
Overload web api action method based on parameter type is not well supported.
But what about attribute based routing ?
You can find out a good example here
Route constraints let you restrict how the parameters in the route template are matched. The general syntax is "{parameter:constraint}". For example:
[Route("users/{id:int}"]
public User GetUserById(int id) { ... }
[Route("users/{name}"]
public User GetUserByName(string name) { ... }
And I think this link must be helpful
Use one route and call the other controller inside from the first controller.

Categories

Resources