How do I use FluentValidation alongside Swagger in .NET Web API application? - asp.net-web-api

I have a .NET Web API project. I was able to add Swagger by installing the Swashbuckle NuGet package. Swagger now makes a nice web page that provides documentation and ability to test by going to this url:
http://localhost:20475/product-catalog-api/swagger/ui/index
This part works great. However, when I add FluentValidation and set it up in the WebApiConfig.cs, all of the requests to my site get high-jacked and instead of seeing the Swagger html page, I only get a JSON with an empty response.
I used this article by Matthew Jones to set up FluentValidation:
http://www.exceptionnotfound.net/custom-validation-in-asp-net-web-api-with-fluentvalidation/
Here is what my web api config looks like:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.Filters.Add(new ValidateModelStateFilter());
config.MessageHandlers.Add(new ResponseWrappingHandler());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: Version + "/{action}",
defaults: new {controller = "Main"}
);
FluentValidationModelValidatorProvider.Configure(config);
}
I could trigger the FluentValidation manually in every web service method, but I would like to have a generic solution like Matthew Jones did with the Filters and MessageHandlers. Basically what I want to do is say IF the request is for swagger-ui then do not route through FluentValidation.

I ended up adding this code inside ResponseWrappingHandler. There may be a more elegant way, but this worked for me. This causes the swagger page request to kick out of the FluentValidation hook.
if (request.RequestUri.AbsolutePath.Contains("swagger"))
{
return response;
}

Related

How to change base url of Swagger in ASP.NET WebApi

By default when you enable swagger in ASP.NET WebApi project is available on URL:
http://localhost:<random_port>/swagger/UI
I would like to use http://localhost:<random_port>/user instead of http://localhost:<random_port>/swagger/UI to access swagger. How/where can I configure that?
I found that for Asp.net core versions we can configure using RoutePrefix, but is there any similar method in ASP.NET Web API:
app.UseSwaggerUI(c =>
{
c.RoutePrefix = "users";
});

Modify Web API action name generated by Swagger

I have a Web API project which is integrated with Swagger. I am using a low code platform IDE OutSystems to consume the REST API.
Outsystems IDE takes following URL to generate REST methods:
http://10.0.0.11/PortalService/swagger/docs/v1
I have the following action method in my web API project:
[HttpGet]
[Route("api/LoanApplications")]
public IHttpActionResult AllLoanApplicationsByUser(string userID, [FromUri]List<string> lstInstitutionId)
For this method Swagger is generating following method name:
Dashboard_AllLoanApplicationsByUser
How to configure Swagger to generate method name similar to the action name from code?
Note: Dashboard is the name of the controller.
Okay. I found the answer here.
This is what I was looking for:
[SwaggerOperation("MethodName")]

ASP.Net Core Web API - ResponseCache attribute is not adding "Cache-Control" header to the reponse

I have multiple controllers in my ASP .NET Core application and I am using ReponseCache attribute like this on a few methods:
//controller
[Route("api/[controller]")]
[EnableCors("CorsPolicy")]
public class InsightsApiController : Controller
//method
[Route("CoursesTextContent")]
[HttpGet]
[DecryptFilter]
[ResponseCache(Duration = 60)]
public IActionResult GetCoursesContent(string locale, string tabKey, string widgetType)
The issue that I am having is that for one controller this is working fine and I can see the response in chrome dev tools with "Cache-Control:public max-age=60" but in a different controller when I add this attribute its adding "Cache-Control:no-cache". I compared both controllers and methods in them and they are configured same. I have also tried to add ASP.NET Core middleware recommended here but same results. I am calling both methods from Angular2 webpage. Is there something I can do from the client side (request)? or something in the ASP.NET Core app setup?
You are missing a trailing parenthesis
[ResponseCache(Duration = 60]
needs to be
[ResponseCache(Duration = 60)]
I had a session middleware enabled in the startup.cs file of my ASNETCore webapi project. I removed it and its working for all calls/controllers now. Not sure why it was causing problem only with one Controller.

owin cors or web api cors

there are 100s of question on CORS on web-api, and on how to enable CORS, there is a different answer each one provides. I am so confused and dont know which answer is correct. And the problem is none of the answers actually explains it point wise, what each line of code does, so that I can understand and solve my problem rather than copy-pasting the code.
anyways, the question is: I am using asp.net web api 2 using owin. And i need to enable CORS. how do I do it? There is cors settings for OWIN
application.UseCors(CorsOptions.AllowAll);
and there is cors settings for asp.net web api
var cors = new EnableCorsAttribute("*", "*", "*", "*");
config.EnableCors(cors);
which one should I use given I am not using OAUTH (I am specifying this because answers on SO differ on when we use OAUTH v/s when we dont use it).
Do i need to enable CORS for both OWIN & WEB-API or only for one of them. There is issue if both are enabled, read here
It would be really helpful if someone can explain me the difference between
OWIN CORS
WEB API CORS
CORS with OAUTH using OWIN/WEBAPI
Also there are answers for self-hosted web api against owin hosted web-api, which further adds to the confution :(, sorry for the rant
You are supposed to use Web API's CORS if you need CORS applied to your API Controllers. For everything else (like a token service) you're stuck with having to use Owin.Cors.
If you end up using both, you'll need to make sure they don't overlap and apply CORS twice to the same request.
Web API 2.2 makes it easy to enable CORS by providing the EnableCorsAttribute.
Basic Usage
[EnableCors("*", "*", "*")]
public class ResourcesController : ApiController
{
...
Attribute definition
[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Method, AllowMultiple = false)]
public EnableCorsAttribute(
string origins,
string headers,
string methods
)
To enable CORS globally use
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("www.example.com", "*", "*");
config.EnableCors(cors);
// ...
}
}
You will also need to install the CORS package from nuget
Install-Package Microsoft.AspNet.WebApi.Cors
There is a way to fix this. Since OWIN and ASP.NET.CORS libraries are working simultaneously. Owin token or authentication method needs to be configured to enable CORS separately from all other API controllers.
Fist thing first, don't use cors with Owin in Startup.cs :
public void Configuration(IAppBuilder app)
{
//app.UseCors(CorsOptions.AllowAll);
Find GrantResourceOwnerCredentials method and add Access-Control-Allow-Origin to context so when it returns a call after authentication is completed that browser finds the header and accepts it.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost" });
Now install Microsoft.AspNet.WebApi.Cors package from Nuget to your webapi project, and add this to Register method
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("http://localhost, ", "accept,accesstoken,authorization,cache-control,pragma,content-type,origin", "GET,PUT,POST,DELETE,TRACE,HEAD,OPTIONS");
config.EnableCors(cors);
Worked for me.

how web Web API in-memory hosting load our controllers classes?

I just learn about Web API in-memory hosting right now, It's new stuff for me. I download the Web API self hosting nuget package and just configure the Routing for Web API and reference the Web API project to In Memory hosting project. And everything is working, but I don't know how in-memory can recognize any controller classes in my Web API project. Is there anyone who can explain me about this?
private HttpServer _server;
private string _url = "http://api.mydomain.com/";
private HttpClient _client;
public PortalWebApiInMemoryTest()
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
_server = new HttpServer(config);
_client=new HttpClient(_server);
}
Basically in Web API for controller probing to occur the assembly having the controllers should be loaded into memory. In your case if your controllers are defined in the same assembly as your in-memory tests, then the assembly would be scanned for all types which implement System.Web.Http.Controllers.IHttpController.
If your controllers are defined in an assembly different from your tests, then you might need to do additional stuff to make sure to have that assembly be loaded into memory. One example is to create a custom IAssembliesResolver like in the following sample:
http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/CustomAssemblyResolverSample/ReadMe.txt

Resources