So I have an application I am working on at work that we have a few hundred clients running on. We are working on a brand spanking new ASP.NET MVC 3 app for it, and I am working on the routes for this app.
I posted recently on a solution I came up with for dynamic routes, and it works fine on a few entries I have in a Sql Express DB. Essentiall it creates routes for every entry that I have in this DB.
So, my question is...If I were to implement this on an enterprise application, would the creation of several hundred if not thousands of routes added into my application have any negative consequences?
Concerning the dynamic route table, there is a recommendation which you seem to follow already:
Use named routes. Named routes are an
optional feature of routing. The names
only apply to URL generation - they
are never used for matching incoming
URLs. When you specify a name when
generating a URL we will only try to
match that one route. This means that
even if the named route you specified
is the 100th route in the route table
we'll jump straight to it and try to
match.
Besides the number of customers / routes, you should also consider the estimated number of requests per day (for which you should be worried more, IMHO), and take into account the scalability of your web server (worker threads, hardware, ...) in consequence.
If you clients use own domains with you application, use custom IRouteConstraint in routes to check request domain and filter only this routes. Tt's solution also protect routing from collisions.
So best way for you to both task - routing request and building links - use cached routing.
You can inherits and extend default MVC Route class
To speedup link building: Override GetVirtualPath that calculate hash from RouteData values and using it to put and get url values to and from cache.
To speedup routing: override GetRouteData also to use cashed RouteDate with url hash.
This solution may be requred more memory, but in most cases you have limited set of url on pages.
You question is slightly unclear. By "dynamic route" do you mean you go to the DB tier on a request to resolve the route or do you query against your db to create the source file for the route table?
In the first case performance should be constant. (The overhead of checking the DB against the number of users you have will not change.) So you should see performance effects right away.
In the second case I expect the routing code will be slower if it has that many items to check -- but it is easy to test.
There is defiantly a performance hit once you start to get over a certain threshold of routes. I don't have any hard benchmarks on this but I have redesigned a few poorly performing sites now.
The more you can use the same route for many different url's with parameters the better.
Just from observation it seems when you start to get close to 1k routes is when it starts really bottoming out.
Related
I have an serverless lambda which does the following:
Start with a set of ids in the query (example.com?ids=a,b,c)
Does HTTP request to another webservice (based on the given ids) which I do not control
Renders the website based on the other webservice response
All works, no issues so far.
Today I introduced a new UI for my website. The user can toggle between "a tableview" and "a listview".
Because those differents views can also be controlled via (another) query paramter, I do a simple "redirect" to my own website. Assuming I'm looking currently at the tableview, for the "show listview" textfield I have a simple <a href="example.com?ids=a,b,c&view=list">[...]<a>.
This redirect leads, of course, to another call to the "other webservice". Even if I can be pretty sure that the content haven't change since my last call (just a few seconds/minutes ago).
My question is:
Can I somehow cache the HTTP requests from my lambda so that we won't do the call again?
I'm somewhat aware of the Cache-Control headers, but since it is an serverless environment it could (and probably will?! I don't know but I don't even care 😅) another machine without this cache. And therefore it will not be an cache hit and will do the requests anyways.
Please don't answer with solutions like "Use JavaScript for changing the UI". I'm aware that this is possible, but my main question is just how (and even if I can) cache such requests in a serverless environment.
Thanks in advance!
From documentation and common best practices we get the impression, that a Serverless function or more specifically an AWS Lambda function has only a very short lifespan. This is to the point, that we need to assume that a function is provisioned into its (firecracker) micro container for a single call only and gets de-provisioned afterwards.
However, to safe resources and to improve performance, the life cycle of a Lambda is rather: provisioning, use for several distinct function calls, de-provisioning.
This means irregardless of the used language, the container gets reused for a certain amount of time. Global resources you create in that time (global variables, static objects, files) will survive beyond a single function call.
Your case
In your exact case you can then implement whichever caching strategy you want. This should work most of the times for your use-case with two pitfalls you need to be aware of:
The micro container gets re-used between requests between different clients. Meaning that of course you need to have a way of access control to your cache, if this is relevant to your use-case.
You do not have direct control over the timeout time of your Lambda, meaning that you should anticipate that every now and then a user will experience the overhead of a non-cached request just due to bad timing.
Let us know about your final solution.
I’m redesigning the REST API for a small SaaS I built. Currently there’s a route /entries that doesn’t require any authentication. However, if the client authenticates with sufficient privileges, the server will send additional information (ex: the account associated with each entry).
The main problem I see with this is that a client attempting to request protected data with insufficient privileges will still receive a 200 response, but without the expected data, instead of a 401 Unauthorized.
The alternatives I came up with are:
Split the endpoint into two endpoints, ex /entries and /admin/entries. The problem with this approach is that there are now two different endpoints for essentially the same resource. However, it has the advantage of being easy to document with OpenAPI. (Additionally, it allows for the addition of a /entries/:id/account endpoint.)
Accept a query parameter ?admin=true. This option is harder to document. On the other hand, it avoids having multiple URIs for a single entry.
Is there a standard way to structure something like this?
Related question: Different RESTful representations of the same resource
The alternatives I came up with are
Note that, as far as HTTP/REST are concerned, your two alternatives are the same: in both cases you are introducing a new resource.
The fact that in one case you use path segments to distinguish the two identifiers and in the other case you are using the query part doesn't change the fact that you have two resources.
Having two resources with the same information is fine - imagine two web pages built from the same information.
It's a trade off - the HTTP application isn't going to know that these resources have common information, and so won't know that invalidating one cached resource should also invalidate the other. So just like with web pages, you can get into situations where the representations that you have in your cache aren't consistent with each other.
Sometimes, the right answer is to use links between different resources - have "the" information in one place, and everywhere else has links that allow you to find that one place. Again, trade-offs.
HTTP isn't an infinitely flexible application protocol. It's really good at transferring documents over a network, especially at "web scale".
There have been attempts at using Link headers to trigger invalidation of other cached resources, but as far as I have been able to tell, none of them has made it past the proposal stage.
Simple ASP.Net AWS Lambda is uploaded and functioning with several gets like:
{proxy+}
api/foo/bar?filter=value
api/foo/barlist?limit=value
with paths tested in Postman as:
//#####.execute-api.us-west-2.amazonaws.com/Prod/{proxy+}
Now want to enable API caching but when doing so only the first api call gets cached and all other calls now incorrectly return the first cached value.
ie //#####.execute-api.us-west-2.amazonaws.com/Prod/api/foo/bar?filter=value == //#####.execute-api.us-west-2.amazonaws.com/Prod/api/foo/barlist?limit=value; In terms of the cache these are return the same but shouldn't be.
How do you setup the caching in APIGateway to correctly see these as different requests per both path and query?
I believe you can't use {proxy+} because that is a resource/integration itself and that is where the caching is getting applied. Or you can (because you can cache any integration), but you get the result you're getting.
Note: I'll use the word "resource" a lot because I think of each item in API Gateway as the item in question, but I believe technically AWS documentation will say "integration" because it's not just the resource but the actual integration on said resource...And said resource has an integration and parameters or what I'll go on to call query string parameters. Apologies to the terminology police.
Put another way, if you had two resources: GET foo/bar and GET foo/barlist then you'd be able to set caching on either or both. It is at this resource based level that caching exists (don't think so much as the final URL path, but the actual resource configured in API Gateway). It doesn't know to break {proxy+} out into an unlimited number of paths unfortunately. Actually it's method plus resource. So I believe you could have different cached results for GET /path and POST /path.
However. You can also choose the integration parameters as cache keys. This would mean that ?filter=value and ?limit=value would be two different cache keys with two different cached responses.
Should foo/bar and foo/barlist have the same query string parameters (and you're still using {proxy+}) then you'll run into that duplicate issue again.
So you may wish to do foo?action=bar&filter=value and foo?action=barlist&filter=value in that case.
You'll need to configure this of course, for each query string parameter. So that may also start to diminish the ease of {proxy+} catch all. Terraform.io is your friend.
This is something I wish was a bit more automatic/smarter as well. I use {proxy+} a lot and it really creates challenges for using their caching.
How can I cache my API responses built with Symfony?
I started to dig into FosCacheBundle and the SymfonyHttpCache, but I'm not sure about my usecase.
You can only access the API with a token in header and every users get the same data in their response for the same URL called (and with the same GET parameters).
I would like to have a cache entry for each of my URL (including get parameters)
and also, is it possible to reorder my GET parameters before the request is processed by my cache system (so that the system dont create multiple cache entries for "URL?foo=bar&foz=baz" and "URL?foz=baz&foo=bar" which returns the same data)
Well there are multiple ways.
But the simplest is this:
If the biggest problem is database access than just caching the compiled result in memcache or similar will go a long way. Plus, this way you stick to your already working authentication.
In your current controller action, after authentication and before payload creation check if there's an entry in memchache. If no, build the payload and save it into memcache than return it. When next request comes along there will be no DB access as it will be returned from memcache. Just don't forget to refresh the cache how ever often you need.
Note:
"Early optimization is the root of all evil" and "Servers are cheaper than programmer hours" are to things to keep in mind. Don't complicate your life with really advanced caching methods if you don't need to.
I am creating a MVC 3 application (although just as applicable to other technologies e.g. ASP.NET Forms) and was just wondering if it is feasible (performance wise) to serve images from code rather than using the direct virtual path (like usual).
The idea is that I improve the common method of serving files to:
Apply security checks
Standardised method of serving files based on route values
Returning modified images (if requested) e.g. different dimentions (ok this would only be used sparingly so don't relate this to the performance question above).
Perform business logic before allowing access to the resource
I know HOW to do it but I don't know IF I should do it.
What are the performance issues (if any)
Does something weird happen e.g. images only load sequentially (maybe that's how HTML does it currently i am not sure - exposing my ignorance here).
Anything else you can think of.
Hope this all makes sense!
Thanks,
Dan.
UPDATE
OK - lets get specific:
What are the performance implications for using this type of method for serving all images in MVC 3 using a memory stream? Note: the image url would be GenericFetchImage/image1 (and just for simplicity - all my images are jpegs).
public FileStreamResult GenericFetchImage(string RouteValueRefToImage)
{
// Create a new memory stream object
MemoryStream ms = new MemoryStream();
// Go get image from file location
ms = GetImageAndPutIntoMemoryStream(RouteValueRefToImage);
// return the output as a file
return new FileStreamResult(ms, "image/jpeg");
}
I know that this method works, because I am using it to dynamically generate an image based on a session value for a captcha image. It's pretty neat - but I would like to use this method for all image retrieval.
I guess I am wondering in the above example if this is ok to do or whether it requires more processing to perform and if so, how much? For example, if the number of visitors were to multiply by 1000 for example, would the server be then processingly burdened in the delivery of images..
THANKS!
A similar question was asked before (Can an ASP.Net MVC controller return an Image?) and it appears that the performance implications are very small to serving images out of actions vs directly. As the accepted answer noted, the difference appears to be on the order of a millisecond (in that test case, about 13%). You could re-run the test locally and see what the difference is on your hardware.
The best answer to your question of if you should be using it is from this answer to (another) similar question (emphasis mine):
DO worry about the following: you will need to re-implement a caching strategy on the server, since IIS manages that for static files requested directly. You will also need to make sure you manage your client-side caching with the correct headers included in the response. Ultimately, just ask yourself if re-inventing a method of serving static files from a server is something that serves your application's needs.
To address the specific cases you provided with the question:
Apply security checks
You can already do this using the IIS 7 integrated pipeline. Relevant bit from documentation:
Allowing services provided by both native and managed modules to apply to all requests, regardless of handler. For example, managed Forms Authentication can be used for all content, including ASP pages, CGIs, and static files.
Standardised method of serving files based on route values
If I'm reading the documentation correctly you can insert a module early enough in the pipeline to re-write incoming URLs to point directly to static resources and let IIS handle the request from there. (For the sake of completeness there also this related question regarding mapping routes to mages: How do I route images using ASP.Net MVC routing?)
Empowering ASP.NET components to provide functionality that was previously unavailable to them due to their placement in the server pipeline. For example, a managed module providing request rewriting functionality can rewrite the request prior to any server processing, including authentication.
There are also some pretty powerful URL rewrite features that come with IIS more or less out of the box.
Returning modified images (if requested) e.g. different dimentions (ok this would only be used sparingly so don't relate this to the performance question above).
It looks like a module that does this is already available for IIS. Not sure if that would fall under serving images from code or not though, I guess it might.
Perform business logic before allowing access to the resource
If you're performing business logic to generate said resources (like a chart) or as you mentioned a captcha image then yeah, you basically have no choice but to do it this way.