Response cache not working with Identity Server 4 - asp.net-core-webapi

I have my startup class configured like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCaching();
...
}
public void Configure(IApplicationBuilder app)
{
app.UseResponseCaching();
...
}
And my controller is like this:
[HttpGet]
[ResponseCache(Duration = 30)] //I normally have a policy here but used duration as an example
[Authorize("Policy_1")]
[Authorize(LocalApi.PolicyName)]
public IActionResult Get()
{
...
}
If I add a breakpoint on my controller method and use postman to send a request the breakpoint is hit and I can see the Cache Control key within the response headers:
If I send the request again the breakpoint IS hit (within the duration).
However, if I remove the Authorize attributes and the auth token from my request everything works as expected.
The authentication and authorization have been set up using identity server 4.
And just to confirm 'Send no-cache header' is off within postman.
So, the question is what do I need to add to get response caching working with identity server 4?

Related

How to ensure API is "warmed up" before first request?

I have a xamarin android app that makes requests to an api hosted on .net core (on IIS on Windows Server). Initial requests ALWAYS take a long time to load (presumably because of some warmup process). How do I ensure that the API is ready to go by the time the user needs to make a request?
Do I just make rapid async get/post requests on app startup? This seems in-efficient...
You need to use health check for your API:
public class ExampleHealthCheck : IHealthCheck
{
public ExampleHealthCheck()
{
// Use dependency injection (DI) to supply any required services to the
// "warmed up" check.
}
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default(CancellationToken))
{
// Execute "warmed up" check logic here.
var healthCheckResultHealthy = true;
if (healthCheckResultHealthy)
{
return Task.FromResult(
HealthCheckResult.Healthy("The check indicates a healthy result."));
}
return Task.FromResult(
HealthCheckResult.Unhealthy("The check indicates an unhealthy result."));
}
}
Add your service to health check services:
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks()
.AddCheck<ExampleHealthCheck>("example_health_check");
}
In Startup.Configure, call UseHealthChecks in the processing pipeline with the endpoint URL:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHealthChecks("/health");
}
Link to documentation: https://learn.microsoft.com/ru-ru/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-2.2

ASP.NET Core Response Caching Not Working As Expected

I'm struggling to get response caching in an ASP.NET Core 2.0 web API working.
I've added response caching in the middleware:
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCaching();
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseResponseCaching();
...
}
Here my action method code:
[ResponseCache(Duration = 30)]
[HttpGet()]
public IActionResult GetLookups()
{
Lookup lookups = dataRepository.GetContactLookups();
}
Here's the postman request and response:
So, I'm getting the correct Cache-Control http header in the response but if I send the response again from postman, it still calls my code in my action method. I expected it to not call my code and use the cached response.
Am I misunderstanding the way that response caching works? Any help would be appreciated.
The problem with Postman you have to disable Send-No-Cash header ( no-cache header makes sure you get the freshest response from your server)
ASP.NET Core 2.0 Web API Response Caching

How I can make private/protected API Using Web API of ASP.NET?

I want to make API(s) using ASP.NET WEB API which should be private or protected.
Using the API(s) I am planning to make Xamarin application and a MVC Website.
Only the Apps can use the API(s), otherwise if anyone get the API(s) then he/she can retrieve data using the API(s). I don't want so!
How can I do it? I need some suggestion.
You can secure you api with API Key Authentication mechanism. Here is a good tutorial
Starting go inside your global.asax.cs file and add
GlobalConfiguration.Configuration.MessageHandlers.Add(new AuthHandler())
Create a class AuthHandler in your project and make that class interface with DelegatingHandler:
public class AuthHandler: DelegatingHandler
Create two methods within your AuthHandler class called ValidateCredentials and SendAsync. The SendAsync method is overridded.
private bool ValidateCredentials(AuthenticationHeaderValue authVal){}
protected override async Task<HttpResponseMessage> SendAsync(HttpResponseMessage request, CancellationToken cancelTok){}
When a class or method has the Authorize filter applied, the MessageHandler in your global.asax is called which calls the Auth handler you created, for example:
[Authorize]
public class SomeController : ApiControler{}
So whats left is the actual authentication of the user. You need to get the header value (placed by the client application), decode it and check it against your database or whatever you use.
private bool ValidateCredentials(AuthenticationHeaderValue authVal)
{
try{
string decodedHeader = new Classes.Strings().decode(authVal);
this.user = // some query to check against database goes here
return true;
}
catch{
// some type of error control here
return false
}
}
protected override async Task<HttpResponseMessage> SendAsync(HttpResponseMessage request, CancellationToken cancelTok)
{
if(ValidateCredentials(request.Headers.Authorization))
{
// store user here to use around the api on this request
}
}
So in short HTTP needs to store your authentication header value. Use that value on each request to filter any class or function you require authentication on. Next, I would read up on http headers, specifically the Authentication header value.

Spring Cloud Netflix : Passing host request parameter via RequestInterceptor to FeignClient

I am building a Spring Cloud project (Brixton.M4 with Spring Boot 1.3.1) with Eureka, Zuul and FeignClient where I am trying to add multi tenancy support (Tenants are identified by subdomain : tenant1.myservice.com). To do so, I would like to somehow pass the original subdomain along requests that are forwarded from a service to the other via Feign but I can't seem to be able to find the right way to do it.
What I have is a client that exposes a #RestController which calls a #FeignClient to communicate with my backend which exposes server operations to the client through its own #RestController.
The #FeignClient using same interface as my #RestController on the server :
#FeignClient(name = "product")
public interface ProductService extends IProductService {
}
What I am currently trying to do is set a header in a RequestInterceptor :
#Component
public class MultiTenancyRequestInterceptor implements RequestInterceptor {
private CurrentTenantProvider currentTenantProvider;
#Autowired
public MultiTenancyRequestInterceptor(CurrentTenantProvider currentTenantProvider) {
this.currentTenantProvider = currentTenantProvider;
}
#Override
public void apply(RequestTemplate template) {
try {
template.header("TENANT", currentTenantProvider.getTenant());
} catch (Exception e) {
// "oops"
}
}
}
My provider class is a simple component where I'm trying to inject a request / session scope bean :
#Component
public class CurrentTenantProvider {
#Autowired
private CurrentTenant currentTenant;
//...
}
The bean (I tried both session and request scope) :
#Bean
#Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public CurrentTenant currentTenant() {
return new CurrentTenant();
}
On the server, I use Hibernate multitenant provider that is supposed to catch the header value and use it to define which DB to connect to :
#Autowired
private HttpServletRequest httpRequest;
#Override
public String resolveCurrentTenantIdentifier() {
return httpRequest.getHeader("TENANT");
}
It seems the Feign call to the server is done in another thread and out of the incoming request scope, so i'm not sure how to pass that value along.
It all works fine when I hardcode the tenant value in the RequestInterceptor so I know the rest is working properly.
I have also looked at many other posts about Zuul "X-Forwaded-For" header and cannot find it in the request received on the server. I have also tried adding a ZuulFilter to pass host name to next request but what I see is that original request to the Client is picked up by the ZuulFilter and I can add but not when the Feign request is sent to the backend service even if I map it in zuul (i guess that is intended ?).
I am not really sure what's the next step and would appreciate some suggestions.
Hope that it's of any use for you but we're doing sth similar in Spring-Cloud-Sleuth but we're using a ThreadLocal to pass span between different libraries and approaches (including Feign + Hystrix).
Here is an example with the highlighted line where we retrieve the Span from the thread local: https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceFeignClientAutoConfiguration.java#L123

Reading http content from POST in MVC 4 WebApi

I have a MVC 4 application, using WebApi. An external client is POST'ing to it, and I need to collect that data. I can get model binding to work with
public void Post([FromBody] Alert alert) { ... }
where Alert is a class defining the complex type. However, I have a case where I want to read whatever is in the body, even when I don't know what the structure is. So how do I read the raw header and body of the incoming POST request. I tried with this:
public void Post(HttpContent content) { ... }
but when POST'ing to the service, the Post method does not get invoked at all.
Input?
Thanks
Try binding HttpRequestMessage instead of HttpContent. That should work and will give you access to the request headers and the body.
public void Post(HttpRequestMessage request) { ... }
You can also access the Request property on your controller which should be set correctly:
public void Post() { var content = Request.Content; }

Resources