Check the method "CreateWritableClone()" in the SDK. You must create a writable clone of the page to be able to write to it. EPiServer return read-only versions of PageData objects for performance.
Can't test it but I guess this will work:
PageData writableCurrentPage = CurrentPage.CreateWritableClone();
int totalHits = Convert.ToInt32(CurrentPage["total_hits"]);
writableCurrentPage.Property["total_hits"].Value = totalHits + 1;
DataFactory.Instance.Save(writableCurrentPage, SaveAction.Publish, EPiServer.Security.AccessLevel.NoAccess);
Hope it helps
/Hans
Exactly! I've been checking souce code from the demo project and found out that I need a writableclone then it works.
Thx to u reply anyway.
Cheers
A follow up question:
I read it here that someone says using property as a hits counter is a bad idea, it will lower down the performance a lot, and he suggested to use tools like Google Statistics or something. Well, in a way I understand why it lowers down the performance, but in our case, we need to use these total hits data to do things, I don't think I can get it from Google Statistics, or?
So, what's a common way to build a hits counter?
One reason why a property is a bad way to store hits is because you will effectively disable caching. When the page is updated the cache is purged, and since you update the page on every hit it will purge the cache on every hit. Another reason is that publishing a page itself spawns a number of operations considerably heaver than reading a page from cache.
I haven't constructed a hits counter myself, but unless there are tools available I would probably use a custom database table to store the hits on a per page/language basis.
And a third reason is that the actual hitcount value is stored in the published page version..
What happens if the editor decides to go back and republish a previous version of the page..? hit count is reset to what value it had back then...
So, all in all, you should definetely store hitcount data _outside_ the pagedata.
/johan
A solution with a HttpModule
Code:
using System; using System.Web; using EPiServer; using EPiServer.Core; namespace YourCompany.EPiServer.Web.HttpModules { public class HitCounterModule : IHttpModule { #region Methods public void Dispose() {} public void Init(HttpApplication application) { application.PostRequestHandlerExecute += new EventHandler(this.OnPostRequestHandlerExecute); } #endregion #region Eventhandlers private void OnPostRequestHandlerExecute(Object source, EventArgs e) { IHttpHandler httpHandler = HttpContext.Current.Handler; if (httpHandler != null && httpHandler is PageBase) { try { PageData currentPage = (httpHandler as PageBase).CurrentPage; // You can now get currentPage.PageLink and the id, increase a counter, and log it somewhere, e.g in a database table. You can use log4net to log in a database table. } catch(Exception exception) { // Maybe you want to log the exception here } } } #endregion } }
Web.Config:
<httpModules>
...
<add name="HitCounterModule" type="YourCompany.EPiServer.Web.HttpModules.HitCounterModule, YourCompany.EPiServer" />
</httpModules>
/Hans
Thx guys
one question, if I create another table, will it bring problems when we updated Episerver? will it still work? I heard that lots of these custom tables don't work correctly after an update. is it so?
No problem, EPiServer wont touch any custom tables.
Modifications to EPiServers own tables is another story, they might get
changed during product upgrades.
/johan
Alright, New table it is!
I don't think pageID or language ID would change, actually, once a page is created it won't be touched at all until it's deleted from the site. That's why we thought of using a property to do hits counts.
Oh, I just mentioned deleting a page, now I got another question:
When u delete a page, all the pages files are still physically there on the VPP folder, so, those files has to be removed manually? Is it designed like that on purpose?
Yeah, it might actually be a better idea to store the hitcount indexed by the page's (relative) url rather than by its id.
This would automatically "migrate" the hitcounts from an old deleted page to a new published under the same url, which is probably a good thing.
You might want to do a migration if a page changes its name, as that would alter its url.
/johan
Hi
I'm making a simple total hits counts using a property, I put thess code in the onload event, but it doesn't do the trick
then I got an error says "The property total_hits is read-only"
Could any1 tell me where I screw up?