Swagger working with a Web API versioning constraint - asp.net-web-api

I have a Web API which configuration adds a versioning constraint like the following:
var constraintResolver = new DefaultInlineConstraintResolver
{
ConstraintMap =
{
["apiVersion"] = typeof(ApiVersionRouteConstraint)
}
};
config.MapHttpAttributeRoutes(constraintResolver);
config.AddApiVersioning();
Then in the controller you can use the constraint:
[ApiVersion("1.0")]
[RoutePrefix("api/v{version:apiVersion}/calendar")]
public class CalendarController : ApiController
{
[HttpGet]
[Route("nextworkingday")]
public IHttpActionResult GetNextWorkingDay(DateTime? date)
{
return Ok();
}
}
That works fine in the API, but swagger will not find any controller. My swagger/docs/v1 would look like this:
{"swagger":"2.0","info":{"version":"v1","title":"SwaggerTest"},"host":"localhost:24460","schemes":["http"],"paths":{},"definitions":{}}
How to configure Swagger to understand the constraint?

Related

why .net core web api methods require HttpMethodAttribute to map to respective request type Get/put/post/delete

I have 2 projects
One is in.NetFramework 4.8
WebAPi SampleController Controller:
namespace Samples.FrameWork.Mvc.Controllers
{
public class SampleController : ApiController
{
// GET: api/Sample
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
}
Other is in .NetCore 2.2
WebAPi SampleController Controller:
namespace Samples.NetCore.WebApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SampleController : ControllerBase
{
// GET: api/Sample
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
}
so.. in Dot NetFrameWork the actions will act based on the name
for the above example have
methods name as
Get(){}
Post(){}
Put(){}
Delete(){}
when above methods are requested based on the request type it will automatically map
to respective method.
but when it comes to .net core web API
it also works but with the help of HttpMethodAttribute.
my question is why does .net core web API methods do not work without HttpMethodAttribute as it works in .net framework?

Ajax not working after deploying to Azure

I am developing a web application using ASP.NET MVC Core. Everything works perfect on my local machine but whenever I deploy to Azure the Ajax calls always get a 404 Not Found.
Here's a snippet of one controller method:
[HttpGet]
public JsonResult GetPublicHolidays()
{
var events = adminService.GetPublicHolidays();
return new JsonResult(events);
}
And here's the Ajax call:
$.getJSON('#Url.Action("GetPublicHolidays","Admin")',
By default, the URL to an action in an ASP.NET Controller is not the name of the method. There's a lot going on by convention in ASP.NET.
As an example, this is a default ASP.NET Core API controller:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}
As you can see in the comment, the route is <baseUrl>/api/values. This route is comprised of the base URL, the api prefix and the name of the controller. Because you add a HttpGetAttribute, ASP.NET knows that is the Get method.
So, considering this controller:
public class RandomController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> WhateverWeirdMethodName()
{
return new string[] { "value1", "value2" };
}
}
The URL for the GET request would be <baseUrl>/api/random

How to access Identity UserManager in Web API Controller to Send an Email

I am using Identity v2 and need to send an Email from Web Api Controller using the UserManager.SendAsync method which is OWIN Middleware component. But I don't know how do I access the UserManager itself in Web Api Controller Method. I am trying a similar approach like a Regular MVC controller but usermanager always null. Any suggestion please?
public class MyApiController: ApiController
{
public MyApiController()
{
}
public MyApiController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public void SendEmail()
{
_userManager.SendAsync(...);
}
}
The constuctor that takes a ApplicationUserManager will never be called with your current solution. Change your empty constructor to call your other constructor.
public class MyApiController: ApiController
{
public MyApiController()
: this(new ApplicationUserManager())
{
}
THE REST OF YOUR IMPLEMENTATION GOES HERE
}
Check whether you have correctly configured UserManager from Startup class
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.DataProtection;
using Owin;
namespace Identity_PasswordPolicy
{
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
///...
// Configure the UserManager
app.UseUserManagerFactory(new IdentityFactoryOptions<ApplicationUserManager>()
{
DataProtectionProvider = app.GetDataProtectionProvider(),
Provider = new IdentityFactoryProvider<ApplicationUserManager>()
{
OnCreate = ApplicationUserManager.Create
}
});
/// ...
}
}
}
Like here in Startup.Auth class from asp.net identity samples
https://aspnet.codeplex.com/SourceControl/latest#Samples/Identity/Identity-PasswordPolicy/Identity-PasswordPolicy/App_Start/Startup.Auth.cs
Startup is partial class and method ConfigureAuth by link is called from https://aspnet.codeplex.com/SourceControl/latest#Samples/Identity/Identity-PasswordPolicy/Identity-PasswordPolicy/Startup.cs
In sample it is called from owin startup method, but depending from hosing it could be called from global.asax.cs

Attribute routing and inheritance

I am playing around with the idea of having a base controller that uses a generic repository to provide the basic CRUD methods for my API controllers so that I don't have to duplicate the same basic code in each new controller. But am running into problems with the routing attribute being recognized when it's in the base controller. To show exactly what the problem I'm having I've created a really simple WebAPI controller.
When I have a Get method in the main Controller and it inherits from the ApiController directly I don't have any problems and this works as expected.
[RoutePrefix("admin/test")]
public class TestController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
When I move the Get method into a base controller it is returning the contents of the 404 page.
[RoutePrefix("admin/test")]
public class TestController : TestBaseController
{
}
public class TestBaseController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
Some more interesting notes:
I can access the action at GET /Test/1. So it is finding it based on the default route still.
When I try to access POST /admin/test, it returns the following JSON
{
"Message":"No HTTP resource was found that matches the request URI 'http://test.com/admin/test'.",
"MessageDetail":"No type was found that matches the controller named 'admin'."
}
Does anyone know of a way to get the routing to work with attributes from a base controller?
Attribute routes cannot be inherited. This was a deliberate design decision. We didn't feel right and didn't see valid scenarios where it would make sense to inherit them.
Could you give a more realistic scenario as to where you would want to use this?
[Update(3/24/2014)]
In the upcoming 5.2 release of MVC Web API, there is going to be an extensibility point called System.Web.Http.Routing.IDirectRouteProvider through which you can enable the inheritance scenario that you are looking for here. You could try this yourself using the latest night builds(documentation on how to use night builds is here)
[Update(7/31/2014)]
Example of how this can be done in Web API 2.2 release:
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
//---------
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
// inherit route attributes decorated on base class controller's actions
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
Using Web API 2.2, you can:
public class BaseController : ApiController
{
[Route("{id:int}")]
public string Get(int id)
{
return "Success:" + id;
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseController
{
}
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
as outlined here: http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22
Got it.
[Route("api/baseuploader/{action}")]
public abstract class BaseUploaderController : ApiController
{
[HttpGet]
public string UploadFile()
{
return "UploadFile";
}
}
[Route("api/values/{action}")]
public class ValuesController : BaseUploaderController
{
[HttpGet]
public string Get(int id)
{
return "value";
}
}
One caveat here is that the route action paramter must be the same as the action name. I could not find a way to get around that. (You cannot rename the route with a RouteAttribute)

Consume ASP WebAPI from ActionResult in different controller

What is the best way to consume WebAPI service from ActionResult in another controller?
Basicaly i have a controller that returns the data.
public class MyApiController : ApiController
{
public MyData Get()
{
//returns the data
}
}
and i want to consume this data from
public class MyConsumeController: Controller
{
public ActionResult MyConsumeAction()
{
var something = //Call Get inside MyApiController
}
}
Any ideas?
Note: I know how to consume it using HttpClient (different project) or jquery (from views).
You could use the client API - the HttpClient class. And here's another sample.

Resources