I am currently utilizing UriInfo, injected by jax-rs framework (currently RestEasy), to build the URI that I use in the Location header. The url created from the UriInfo is also used in the response xml/json.
So in short it looks some thing like:
public class ResourceBean {
#Context
private UriInfo uriInfo
public Response mappedMethod(){
...
UriBuilder builder = uriInfo.getBaseUriBuilder().path(...);
...
}
}
The problem is that we use load balancers in front of the application servers and if a user/system is to follow one of the links it needs to go via the load balancers and not directly to this machine. uriInfo.getBaseUriBuilder() returns the base URL of the current machine and not of the load balancers.
I understand that some load balancers can do url rewritting to achieve this, but I unfortunately don't have any control or access to our load balancers and don't know if they support it, or if it is even possible in the body of the html response.
Is there a central point where the UriInfo can be manipulated or contstructed to contain the load balancer's base URI?
I have found where the UriInfo is constructed. The information is gathered from HttpServletRequest. Unfortunately there is no way other then changing RestEasy code to manipulate it.
So I am going to use a Servlet Filter to manipulate the request before it hits the framework.
Related
having a rewrite rule like this:
public class MyRule : IRule
{
public void ApplyRule(RewriteContext context)
{
var path = context.HttpContext.Request.Path;
///var controllerName = ???
}
}
how do I get the controller and action name ?
in Startup.cs /Configure I have:
var rewriter = new RewriteOptions().Add(new MyRule());
app.UseRewriter(rewriter);
app.UseStaticFiles();
app.UseMvc(
...
Rewrite Rules wont know anything about the controller and action.
It is way too early in the pipeline to know anything about MVC routing and is usually associated with rewriting to resources based on a pattern defined for the request.
URL rewriting is the act of modifying request URLs based on one or more predefined rules. URL rewriting creates an abstraction between resource locations and their addresses so that the locations and addresses aren't tightly linked.
URL rewriting is valuable in several scenarios to:
Move or replace server resources temporarily or permanently and maintain stable locators for those resources.
Split request processing across different apps or across areas of one app.
Remove, add, or reorganize URL segments on incoming requests.
Optimize public URLs for Search Engine Optimization (SEO).
Permit the use of friendly public URLs to help visitors predict the content returned by requesting a resource.
Redirect insecure requests to secure endpoints.
Prevent hotlinking, where an external site uses a hosted static asset on another site by linking the asset into its own content.
Reference URL Rewriting Middleware in ASP.NET Core
I want to host two version of my ASP Core website on the same VPS, one for each supplied environement (Staging and Test). I would like both web sites to be accessible from a subfolder of the same URL:
http://www.mywebsite/Staging
http://www.mywebsite/Test
After reading a lot I found the following Github issue: https://github.com/aspnet/Hosting/issues/815
This tip works but for AJAX calls it crashes: Indeed, the JavaScript calls are not aware of this new path (BUG?). All requests are sent to the root base path (ignoring /Staging or /Test).
I partially solved it usig a middleware that redirects my AJAX calls to the correct path. It works for GET requests but it obviously fails for POST request that have a body.
Note that if we don't redirect, and just change the original PathBase request in the middleware, if the API call needs any authentication schema, it will throws a 401 error: The original PathBase is the root / where the response has a different path base, i.e. /Staging, then the cookie in the header prevents from this cross path base request/response.
Could someone tell me what is the recomanded practice to achieve my needs?
Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env
{
app.UsePathBase($"/{env.EnvironmentName}");
...
}
My Middleware :
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers[RequestedWithHeader] == XmlHttpRequest)
{
if (string.IsNullOrEmpty(context.Request.PathBase))
{
if (context.Request.Method == HttpMethod.Post.Method)
{
// Do what ?
}
else
{
//Get request : set environement name + original path + original query string
context.Response.Redirect(context.Request.Path.ToString().Insert(0, "/" + _env.EnvironmentName) + context.Request.QueryString);
return;
}
}
}
}
Of course, your client-side code will not be able to automatically change its code based on the path base that is active for the current request. JavaScript code is (usually) static content, so unless you actually rewrite the code dynamically, it cannot update URLs that are embedded inside.
You could determine the base path from the current request’s URL but that is a rather fragile solution since you need to find a logic that will work regardless of where in the application you are. So doing so is not recommended.
The overall problem is that on the client-side, there is no concept of a path base (or even an environment). So you will have to transfer that knowledge from the server to the client. And just like the path base is set for the server-side code using the path base middleware, you will need some server-side code that will pass the path base to the client-side code.
What I personally do is just configure the root path to the API in the application layout. So my _Layout.cshtml contains the following line:
<body data-api="#Url.Content("~/api/")">
That way, I can then retrieve the root path to the API using document.body.dataset.api in JavaScript. My AJAX calls are then all made so they respect that value. That way, I can host the site at any path, and the AJAX calls will use the proper path too.
You could also just use "~" as the content path to just refer to the root of your application. And you could also expose this value in a JavaScript variable inside a <script> block instead, if you prefer that.
In ASP.NET Core application I have a action method that returns some data. I wanted to cache this data on client side. So based on the documentation here i can use ResponseCache attribute on the action method. This attribute adds Cache-Control header in response
Response caching refers to specifying cache-related headers on HTTP
responses made by ASP.NET Core MVC actions. These headers specify how
you want client and intermediate (proxy) machines to cache responses
to certain requests (if at all). This can reduce the number of
requests a client or proxy makes to the web server, since future
requests for the same action may be served from the client or proxy’s
cache.
also
Response caching does not cache responses on the web server. It
differs from output caching, which would cache responses in memory on
the server in earlier versions of ASP.NET and ASP.NET MVC.
So this is how my action method looks
public class LookupController : Controller
{
[HttpGet]
[ResponseCache(Duration = 120)]
public IEnumerable<StateProvinceLookupModel> GetStateProvinces()
{
return _domain.GetStateProvinces();
}
}
Then i call the method using browser as http://localhost:40004/lookup/getstateprovinces
Here is the request and response headers
Notice that Response Headers has Cache-Control: public,max-age-120 as expected.
However if refresh the page using F5 (before 120 seconds), the debugger breakpoint inside GetStateProvince action method alway hits. That means its not cahing the data on client side.
Is there anything else i need to do to enable client side caching?
Update
I have tried using IE, Chrome and also POSTMAN with no luck. Everytime i type the url in address bar or hit refresh the client ( that is browser or postman) makes a call to action method.
Actually ResponseCache attribute works as intended.
The difference is that the response is cached if you navigate through your website pages (case 1), or use back and forward buttons (not when refreshing the page).
As an example of case 1, I have the following:
you're on page http://localhost:65060/Home/Index
type another url and click enter or click a link in your webpage: http://localhost:65060/Home/Users
type again the url http://localhost:65060/Home/Index (you will see that this time the response for this url gets fetched from disk cache)
As you will see in the article Response Caching in ASP.Net Core 1.1, the following is stated:
During a browser session, browsing multiple pages within the website or using back and forward button to visit the pages, content will be served from the local browser cache (if not expired).
But when page is refreshed via F5, the request will be go to the server and page content will get refreshed. You can verify it via refreshing contact page using F5.
So when you hit F5, response caching expiration value has no role to play to serve the content. You should see 200 response for contact request.
References:
[1]. ASP.NET Core Response Caching Sample
[2]. ResponseCache attribute sample
[3]: How to control web page caching, across all browsers?
Long story short, using the ResponseCache attribute like the following is sufficient to get expiration-based client-side caching to work in a brand new, default dotnet core project (including async methods):
[HttpGet]
[ResponseCache(Duration = 120)]
public IEnumerable<StateProvinceLookupModel> GetStateProvinces()
{
return _domain.GetStateProvinces();
}
This is working correctly in the screenshot above, as the Cache-Control: public,max-age=120 is visible there. In most cases, browsers won't send subsequent requests before the expiration (i.e. for the next 120 seconds or 2 minutes), but this is a decision of the browser (or other client).
If the request is sent regardless, you either have some middleware or server configuration overwriting your response headers, or your client ignores the caching directive. In the screenshot above, the client ignores caching, because the cache control header is there.
Common cases where the client cache is ignored and the request is sent:
Chrome prevents any kind of caching when using HTTPS without a certificate (or an invalid certificate, this is often common for local development, so make sure to use HTTP when testing your cache, or trust a self-signed cert)
Most browser dev tools disable caching by default when open, this can be disabled
Browsers usually send additional headers, Chrome sends Cache-Control: no-cache
Refreshing directly (i.e. Ctrl+F5) will instruct most browsers to not use a cache and make the request regardless of age
Browsers usually send additional headers, Chrome sends Cache-Control: max-age=0 (this is visible in your screenshot)
Postman sends the Cache-Control: no-cache header which makes it bypass the local cache, resulting in requests to be sent; you can disable it from the settings dialog, in which case requests will no longer be sent with the above client cache configuration
At this point we are beyond expiration-based client caching, and the server will receive the request in one way or another, and another layer of caching occurs: you may make the server respond with a 304 Not Modified code (which is then again up to the client to interpret in whatever way it wants) or use a server-side cache and respond with the full content. Or you may not use any subsequent caching and just perform the entire request processing again on the server.
Note: the ResponseCache attribute is not to be confused with services.AddResponseCaching() & app.UseResponseCaching() middleware in startup configuration, because that is for server-side caching (which by default uses an in-memory cache, when using the middleware). The middleware is not required for client-caching to work, the attribute by itself is enough.
First of all I want to clarify few thing and I am sure that you already knew it.
ResponseCache is not equal to OutputCache any way.
ResponseCache is as per my thinking set header but it does not cache anything on server side.
Now If you want to Cache same as OutputCache then you might have to use preview release 1.1 that just release.
ASP.net core 1.1 preview release
https://blogs.msdn.microsoft.com/webdev/2016/10/25/announcing-asp-net-core-1-1-preview-1/
They introduce new Response Caching Middleware. Response Caching Middleware
Demo of it available here . https://github.com/aspnet/ResponseCaching/blob/dev/samples/ResponseCachingSample/Startup.cs
Using 4.0.31, my AppHost Configure method is declared like this:
public override void Configure(Funq.Container container)
{
HostConfig hc = new HostConfig()
{ HandlerFactoryPath = "api", UseHttpsLinks = true };
SetConfig(hc);
Plugins.Add(new CorsFeature());
Plugins.Add(new SwaggerFeature());
...
}
I was under the impression that this would set the url for swagger-ui to be the https version of ../api/resources, however I'm still getting the regular http endpoint in the swagger URL textbox, like:
http://example.com/myapp/api/resources
Our web servers are behind load-balancers that perform SSL offloading (and require SSL), so the URL should be:
https://example.com/myapp/api/resources
On a positive note, using 'UseHttpsLinks' actually allows swagger-ui to function once you fix the endpoint url. It didn't work at all without it!
I'm overriding the swagger url property using a replacement index.html via the Virtual File System as a hack -- since in the development, QA, and staging environments, the url property is pointing to production...(not so good)
Config.UseHttpsLinks has been expanded to also apply to the BaseUrl where it now changes http:// urls to https:// in this commit.
This change is available from v4.0.33+ that's now available on MyGet.
I am attempting to use an S3 bucket as a deployment location for an internal, auto-updating application's files. It would be the location where the new version's files are dumped for the application to puck up on an update. Since this is an internal application, I was hoping to have the URL be private, but to be able to access it using only a URL. I was hoping to look into using third party auto updating software, which means I can't use the Amazon API to access it.
Does anyone know a way to get a URL to a private bucket on S3?
You probably want to use one of the available AWS Software Development Kits (SDKs), which all implement the respective methods to generate these URLs by means of the GetPreSignedURL() method (e.g. Java: generatePresignedUrl(), C#: GetPreSignedURL()):
The GetPreSignedURL operations creates a signed http request. Query
string authentication is useful for giving HTTP or browser access to
resources that would normally require authentication. When using query
string authentication, you create a query, specify an expiration time
for the query, sign it with your signature, place the data in an HTTP
request, and distribute the request to a user or embed the request in
a web page. A PreSigned URL can be generated for GET, PUT and HEAD
operations on your bucket, keys, and versions.
There are a couple of related questions already and e.g. Why is my S3 pre-signed request invalid when I set a response header override that contains a “+”? contains a working sample in C# (aside from the content type issue Ragesh is experiencing of course).
Good luck!