IIS 7, three bindings, how i can do three caches for them? - asp.net

Question about settings of IIS7. How I can do one cache for each of bindings? For example, I have one site and three bindings for the site. I need to create three different caches for each of three bindings.

Use Request.Host as part of the cache key.

usr's answer is correct if you are manually reading from and writing to the cache. You have less direct control over the cache key with the OutputCacheAttribute, however.
Note that the OutputCacheAttribute still relies on cache keys in its implementation. In ASP.NET, each item that is cached is assigned a key through which it is looked up.
When you call a Controller Action that has an OutputCacheAttribute, a cache key is generated based on your request; for instance, if you have some VaryByParam designations, cache keys can differ for each user. Then the response your Action returns is stored in the cache under that key.
When the next request comes in, the cache key is generated and we check in the cache to see if there is already something cached under that key. If so, we just return that; otherwise, we continue with the Action.
We can have a different cache for each binding by including the host name in the cache key. If you're using OutputCacheAttribute, you can override it to allow varying the cache by host:
public override string GetVaryByCustomString(HttpContext context, string customVary)
{
if(customVary == "Host")
{
return context.Request.Url.Host;
}
// other behaviors here if necessary
return "";
}
This will allow the cache key to be dynamically modified to include the host name through which the site is accessed. This means that if you have three different bindings, you will have three different cache keys (assuming no other varying parameters).
Here's how to modify your Controller Action:
[MyOutputCache(VaryByParam = "None", VaryByCustom = "Host", Duration = 7200)]
public ActionResult Index()
{
// ...
return View();
}
Notice the inclusion of VaryByCustom = "Host", which is then seen by your overriden OutputCacheAttribute's GetVaryByCustomString() method and thus included in the cache key that is used.

Related

How can i do custom authorization in my ASP.NET MVC application

I am making a small SAAS application. I am using the same database for all users and only differentiating between the data using username and ids. This means that the user can type in a new url in the browser and see other users data. This, of course is not a desirable approach. I would like to do a check to see if the current user can actually access the resources: eg.
http://myapplication.com/images/15
And if the user changes the url to
http://myapplication.com/images/16
I should do a check in my database to see if the current user actually has access to see the images with user id 16. And if not redirect to a "not authorized" page.
How do I implement this?
The first step is to make sure that you never have any ID's for the user itself in the url. For instance, never have http://example.com/?user=10. You should always get the users id from their authentication rather than from the URL (or posted values either).
The second step, is to use that ID in your queries. So, for instance, let's say they seek http://example.com/images/100, then in your database you should have a mechanism that links the asset's ownership to the user, either a userid or a mapping table of id's to asset's, etc.. This way, if the user isn't allowed access, it will just return an empty result set. It's impossible for the data to be returned, and the empty result set should tell your page that the item doesn't exist (not necessarily an authorization failure, just that the object doesn't exist).
Third, any pages which are inherently about the user, such as a user profile, account page, or dashboard should never have any ID's at all in the URL, it should just automatically go to the authenticated users page.
Finally, if you need to prevent the user from accessing an entire page or set of pages, then you should do this in the OnAuthorization event or similar (custom attribute, base class, etc..) or using the built-in attribute authorization and use role based authorization. Never do authorization in the PageLoad or similar event (such as the controller action), because by the time you get to that step a lot of work has already happened in the pipeline. It's best to block access long before the page even starts to setup. Authorization events happen at the very beginning of the pipeline.
Make an Action that check userId and returns error page or file
public FileResult Image(string imageName)
{
string UserId = MethodWhereYouGetCurrentUserID();
if(imageName == null) return View("~/Views/Shared/Error.cshtml", (object)"Null image");
string imageShortName = imageName.Split(".")[0];
if(!UserId == imageShortName) return View(~/Views/Shared/Error.cshtml, (object)"You can't access to this");
string path = Server.MapPath("~/Contant/images/"+imageName);
return File(path, "image/jpg");
}
RouteConfig file
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute
(
name: "ImageRoute",
url: "/images/imageName",
default: new {controller = "Home", action = "GetImage"}
);
}

System.Web.Caching.Cache in ASP.NET

I just discovered System.Web.Caching.Cache used in a project that I am working on and I am having a hard time finding more information on it.
My question is how this cache is persisted? Is it client-side (similar to ViewState), server-side (Session)? Entirely different?
Example:
protected string FileContent
{
get
{
return Cache[FILE_UPLOAD_KEY + Id] as string ?? GetFileUpload();
}
}
It's a server-side, application-wide cache.
One instance of this class is created per application domain, and it
remains valid as long as the application domain remains active.
Information about an instance of this class is available through the
Cache property of the HttpContext object or the Cache property of the
Page object. (Cache Class, MSDN)
It grants the ability to set time limits and so forth on cached objects. And it doesn't promise the object will be there when you need it again. It keeps items in cache only so long as there is sufficient memory to do so.
So, it's not intended for passing objects between page views (use ViewState or Session for that) or controls (use Items for that). It's intended to cache global objects (accessible in any request from all clients) that are expensive to build.
It's persisted at the server, and it's global across sessions, like Application. So when you set a value in the Cache, it's available to all users until it expires.
EDIT
The example you've got probably isn't quite right (unless GetFileUpload() actually writes to the cache). Generally your calls to cache look something like:
string GetSomeStringFromCache()
{
string someString = Cache[SomeKey] as string;
if (someString == null)
{
someString = GetStringUsingSomeExpensiveFunction();
Cache.Add(SomeKey, someString, /*a bunch of other parameters*/);
}
return someString;
}
This will put it in the Cache if it's not already there, but if it is, it will just use it.

TempData implementation changes - Reasons for the change

In ASP.NET MVC 2, the lifespan of an entry in the TempDataDictionary was just one HTTP Request.
That translated to setting a value in one request, redirecting, and having access to the same item at the other end of the line. After this the entry would be no longer available, regardless of whether you read the value out of the dictionary at the latter end of the line or not.
Since ASP.NET MVC 3 (I believe), this implementation detail has changed quite significantly.
Entries in the TempDataDictionary are now only removed once they've been read.
MVC 4
public object this[string key]
{
get
{
object obj;
if (!this.TryGetValue(key, out obj))
return (object) null;
this._initialKeys.Remove(key);
return obj;
}
}
and
public bool TryGetValue(string key, out object value)
{
this._initialKeys.Remove(key);
return this._data.TryGetValue(key, out value);
}
MVC 2:
public object this[string key] {
get {
object value;
if (TryGetValue(key, out value)) {
return value;
}
return null;
}
and
public bool TryGetValue(string key, out object value) {
return _data.TryGetValue(key, out value);
}
Since most people seem to put items in the TempData collection in one request and immediately read them back out in the immediate next request, the functionality seems roughtly the same.
In scenarios where this is not the case such as wanting to read the TempData entry if redirected to one place, and expecting it to have been removed if requesting other resources and navigating back, this change has quite an impact.
No longer is the entry available for one http request but is available over many HTTP requests, be it only available to one single get on the dictionary.
I'd like to know more about this implimentation change, what were the reasons for the change, was this simply to cater for multiple redirects or are there deeper benefits?
Secondary to that, I'm intrigued to know if there's anything built in that now caters for single HTTP request sharing of data in the same way that TempData used to cater for?
You're correct that TempData keys are only cleared if they’ve been read (or after the user’s session expires) but this has been the case since MVC2, (http://forums.asp.net/post/3692286.aspx)
I'd like to know more about this implimentation change, what were the
reasons for the change, was this simply to cater for multiple
redirects or are there deeper benefits?
This change prevented problems that arose in MVC 1, such as TempData keys being deleted before they were read. So yes, the primary benefit is in avoiding these problems when you have multiple re-directs, or interleaved requests. In addition, the RedirectToRouteResult or RedirectResult methods now automatically call TempData.Keep() to prevent clearing of keys, even after they've been read so keep that in mind as well.
In scenarios where this is not the case such as wanting to read the
TempData entry if redirected to one place, and expecting it to have
been removed if requesting other resources and navigating back, this
change has quite an impact.
You’re correct, if you've been coding under the assumption that the TempData keys are cleared automatically you could run into unexpected problems. You can call TempData.Clear() to manually remove all keys from the TempDataDictionary, or TempData.Remove(key) to remove a specific key. You can also use TempData.Peek() to read the value of a TempData key without flagging it for removal from the TempDataDictionary.
Secondary to that, I'm intrigued to know if there's anything built in
that now caters for single HTTP request sharing of data in the same
way that TempData used to cater for?
I'm not aware of any new objects or functions that replicate the original implementation of TempData. Essentially we still use TempData but have to be mindful that the data persists until read and clear the dictionary manually if needed.

Use of HttpValidationStatus.IgnoreThisRequest

I am studying the cache invalidation mechanisms and came across the HttpValidationStatus.IgnoreThisRequest.
I understand, that when this is specified, ASP.Net is going to treat response as Cache miss.
Another point is that the dynamic value received in this response is not going to replace the existing cache, as a result subsequent requests are going to use the already cached result.
What is the use of such a mechanism?
Why would someone want to use the already cached result even after having the latest ones?
The use of HttpValidationStatus.IgnoreThisRequest. is meant for cases when you don't want to show a cached page only for that request.
Example:
public void Page_Load()
{
Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(ValidateCache), null);
}
public static void ValidateCache(HttpContext context, Object data, ref HttpValidationStatus status)
{
validationstatus = context.Request.IsAuthenticated ? HttpValidationStatus.IgnoreThisRequest : HttpValidationStatus.Valid;
}
In this case I want to serve cached pages to everybody except for logged users.
Think about a cms: i maybe want that an editor see the just edited page and not the cached one.

Is it possible to make a webservice per user?

I have a webservice (.asmx) and I want it to retain a value on a per-user basis. Is this possible?
ie (pseudo-code)
MyWebservice
{
object perUserVariable = something;
[WebMethod]
public void myMethod()
{
if (something == null)
{
something = doBigExpensivedatabaseCall();
}
return something;
}
}
You can use ASP.NET's session mechanism.
Change your WebMethod attribute, so that it will look like that:
[WebMethod(EnableSession = true)]
This is normally achieved by cookies, or by sending the session id in the query string (both ways are completely handled by ASP.NET). The former is the default, to achieve the latter, just set cookieless="true" in your config.web file.
Yes, you would need to pass in some kind of user identifier to specify who the user is, do your operation and instead of storing it in something you will to use a durable or semi-durable store such as Cache or Session. Then look that value up from the Cache or Session instead of a local member.
Also fwiw the way you have that configured the fact something isn't static means it would be null on every single request because it would be newly initialized. Making it static however would then server the individual instance of something to each and every request there after.
This is why you need to use a store that can differentiate on the user such as Cache[userid+"something"] or the Session["something"] instead.
Your choices seem to be using some type of caching system like session or memcache.
Session will require a session id passed as a cookie to the requests. Other caching providers could probably key off of a post value like the userid.

Resources