Cache is a tpe and cannot be used as an expression error

S

Steve Franks

I see several reference to using the ASP.NET 2.0 Cache object in C# where
the documentation just shows snippets like this:
if (Cache["sometoken"] == null)
... do something

However when I use this code in a C# class that is called from an ASP.NET
page, the compiler gives this error:
'Cache' is a tpe and cannot be used as an expression

Furthermore when I type in Cache and press the "." for intellisense, the
only things that pop up are Equals, NoAbsoluteExpiration,
NoSliderExpiration, ReferenceEquals. No methods like Add, Insert and so
forth show up.

This drove me crazy for a while. Then I decided to try my cache code
directly in my ASP.NET code behind page and it worked just fine.

Eventually after mucking around for a while I found that if I did this in my
C# class file then things worked correctly:

public Cache MyCache;
MyCache = System.Web.HttpContext.Current.Cache;

and now I can use if (MyCache["sometoken'] == null) from my C# class and it
works just fine.

A couple of questions:

1) Is this really necessary or am I referencing or doing something in
correctly?

2) Is there another approach to accessing the Cache from a C# class called
by a ASP.NET code behind, or did I stumble upon the right approach by what I
am using here?

Hopefully I'll get some clarification as to what is/was going on and why
this was necessary, and hopefully someone will find this post one day and it
will save them a lot of time.

Thanks,

Steve
 
S

S. Justin Gengo

Steve,

That's what you had to do. The Cache object is used by the .aspx page
natively and therefore the object has already been instantiated. In a class
file the Cache object is not already being used so you had to explicitly
create a holder for it and then get the cache object being used on the page.

Short story, you're doing it exactly right.

--
Sincerely,

S. Justin Gengo, MCP
Web Developer / Programmer

www.aboutfortunate.com

"Out of chaos comes order."
Nietzsche
 
T

The Crow

be sure System.Web.dll is references by project your class is in, and to get
the current Cache object being used by the asp.net, call
System.Web.HttpContect.Current.Cache
 
S

Steve Franks

Thanks. On a related note, I am now having difficulty getting to the Page
object within the same C# class that is called from my ASP.NET code behind.

For example, I can do the following just fine in my ASP.NET code behind:
Repeater1.ItemTemplate = Page.LoadTemplate("mytemplate.ascx");

However I want to be able to do the same thing from my C# class, but I
cannot figure out how to hook into the current Page instance from within my
C# class.

For example, when it came to the Cache object, I figured out that I had to
use System.Web.HttpContext.Current.Cache to hook into the Cach object
instance. I assume I need to do something similar to get at the current
Page object?.

I've been poking around but there is no System.Web.HttpContext.Current.Page
object and I can not figure out how to tap into the current Page so that I
can do a Page.LoadTemplate from my C# class.

Can you please advise on what I am missing? Thanks!

Steve
 
T

The Crow

it sounds like a bad design, contolling controls of the page outside the
page. but maybe you can try to add the Page to Session in Global.asax
Application_BeginRequest. then you can access it by
(System.Web.UI.Page)System.Web.HttpContext.Current.Session["CurrentPage"];
 
S

Steve Franks

I don't think its a case of a bad design. I have a utility class used for
various supporting functions that I need to access through my ASP.NET
application.

Some of my pages used Page.LoadTemplate. In this particular case, I want to
write a helper function that performs the LoadTemplate and then stores the
result in the Cache. In subsequent requests for this template the utility
class will return the cached version. Since different ASP.NET pages need
this functionality, I'm trying to centralize this in this C# utility class.

Anyone know how Page.LoadTemplate can be used from a C# class? Details on
what I'm trying to do are in my previous post on this topic.

Thanks,

Steve
 
T

The Crow

you can inherit from System.Web.UI.Page and extend the base functionalty.
and then other Page classes in your application those need this functionalty
inherits from that class instead of directly inheriting from Page class.. i
usualy sense bad designs at the beginning. and all i try to do is help you.
happy programming :)
 
S

Steve Franks

Sounds like a great idea, thanks! I don't think I'm doing this right though.
Here is what I did so far:

1) I created a new class called SuperPage. Here is the source:

public class CustomPage : System.Web.UI.Page
{
public CustomPage()
{
}
public new ITemplate LoadTemplate(string filename)
{
// TODO: Retrieve from Cache if previously loaded
ITemplate iTemplate = base.LoadTemplate(filename);
// TODO: Store into Cache if was not previously loaded
return iTemplate;
}
}

2) I then changed my ASP.NET code behind page to derrive from SuperPage
instead of Page, by doing this:

changed:
public partial class mytest : System.Web.UI.Page

to
public partial class mytest : CustomPage

Inside my Page_Load event in the ASP.NET I have this line:
ITemplate itemTemplate = Page.LoadTemplate("myTemplate.ascx");

OK, those are the changes I made, and put a breakpoint in the constructor of
CustomPage and CustomPage's LoadTemplate so I could be sure it was being
called.

Unfortunately this is not working. The challenge I'm having is that when I
run my page, the debugger does stop in my CustomPage constructor. However
when this code executes:
ITemplate itemTemplate = Page.LoadTemplate("myTemplate.ascx");
my LoadTemplate method is not getting called.

Apparently the origional Page's LoadTemplate is getting called and my custom
one never is...

So then I thought that maybe the problem was the I was still using
"Page.LoadTemplate" and that instead I needed to do this in my ASP.NET page:
CustomPage cp = new CustomPage();
ITemplate itemTemplate = cp.LoadTemplate("myTemplate.ascx");

However this did not work either. Although CustomPage's LoadTemplate does at
least get called, it throws a nullreference exception on this line saying
that parameter "basepath" cannot be null:
ITemplate iTemplate = base.LoadTemplate(filename);

I don't understand why this is null anyway, since CustomPage derrives from
Page, so I should be able to refer to the base set of methods and properties
using "base" right?

At any rate I think using cp.LoadTemplate is likely the wrong approach since
it doesn't make sense that I'd have to create a new instance of a CustomPage
to call LoadTemplate when the ASP.NET page derrives from CustomPage in the
first place.

As you can see I'm quite confused :) but I think some of my approach is
right and perhaps I'm just missing one part? At any rated I'd greatly
appreciate hearing back on what you think I'm messing up.

Thanks very much for your time! It is greatly appreciated.

Steve
 
T

The Crow

Steve Franks said:
Sounds like a great idea, thanks! I don't think I'm doing this right
though. Here is what I did so far:

1) I created a new class called SuperPage. Here is the source:

public class CustomPage : System.Web.UI.Page
{
public CustomPage()
{
}
public new ITemplate LoadTemplate(string filename)
{
// TODO: Retrieve from Cache if previously loaded
ITemplate iTemplate = base.LoadTemplate(filename);
// TODO: Store into Cache if was not previously loaded
return iTemplate;
}
}

things seems OK up to here.
2) I then changed my ASP.NET code behind page to derrive from SuperPage
instead of Page, by doing this:

changed:
public partial class mytest : System.Web.UI.Page

to
public partial class mytest : CustomPage

Inside my Page_Load event in the ASP.NET I have this line:
ITemplate itemTemplate = Page.LoadTemplate("myTemplate.ascx");

Here, the referense "Page" is of kind "System.Web.UI.Page".. Since
LoadTemplate method is not virtual you used new keyword. Calling it via base
type's reference calls "original version" of the method because polimorphism
is not at charge here.. you shoul dcall that method after casting to
CustomPage > ((CustomPage)Page).LoadTemplate or if you are calling it within
Page instance you can directly call this.LoadTemplate.. Or you can inclue
public new CustomPage Page
{
get{return (CustomPage)Page;}
}
then it should be ok.

By the way, if templates you are talking about are just user controls, why
dont you use Page's-User Control's output caching mechanism? you can do that
by adding <%@ OutputCache Duration="60"> direction in your usercontol file.
you can customize caching options.. check msdn for further info.
 
S

Steve Franks

things seems OK up to here.


Here, the referense "Page" is of kind "System.Web.UI.Page".. Since
LoadTemplate method is not virtual you used new keyword. Calling it via
base type's reference calls "original version" of the method because
polimorphism is not at charge here.. you shoul dcall that method after
casting to CustomPage > ((CustomPage)Page).LoadTemplate or if you are
calling it within Page instance you can directly call this.LoadTemplate..
Or you can inclue
public new CustomPage Page
{
get{return (CustomPage)Page;}
}
then it should be ok.

Thanks but unfortunately I am not able to follow any of that :) What
specifically do I need to add to my code? Not sure what I am supposed to do
with "CustomPage > ((CustomPage)Page).LoadTemplate" or where it should go.
Likewise for:
public new CustomPage Page
{
get{return (CustomPage)Page;}
}

That would go in my CustomPage class and automatically make things work?
By the way, if templates you are talking about are just user controls, why
dont you use Page's-User Control's output caching mechanism? you can do
that by adding <%@ OutputCache Duration="60"> direction in your usercontol
file. you can customize caching options.. check msdn for further info.

Yes, they are user controls. In summary, I am using the Repeater control.
I need to place over a dozen different repeater controls on the same page to
create several html tables of output, with each table holding a different
category of results.

So instead of having to hard code the ItemTemplate and
AlternatingItemTemplate values, what I did was place the templates into
their own .ascx file. Then I use this:
Repeater1.ItemTemplate = Page.LoadTemplate("mytemplate.ascx");
Repeater1.AlternatingItemTemplate =
Page.LoadTemplate("mytemplateAlt.ascx");
Repeater2.ItemTemplate = Page.LoadTemplate("mytemplate.ascx");
Repeater2.AlternatingItemTemplate =
Page.LoadTemplate("mytemplateAlt.ascx");

So the whole purpose of my trying to do this caching was to prevent the
LoadTemplate from going to disk every time.

Are you saying that if I add those caching options to the @ directive in the
..ascx that it will accomplish this caching for me? What would make sense,
as I was surprised I had to do this on my own giving the new Cache control
that was added.

Thanks,

Steve
 
S

Steve Franks

OK after playing with this some more I figured out what you meant by using
((CustomPage)Page).LoadTemplate - it works great - thanks!

Also regarding the other approach of:
public new CustomPage Page
{
get{return (CustomPage)Page;}
}

I got that to work, but I had to change the one line to read this instead:

get{return (CustomPage)this;}

Otherwise it was getting stuck in an indefinite loop.

Ultimately I decided to go with the casting instead. Althought the approach
which uses get{return (CustomPage)this;}is more elegant and clean, I thought
the casting way made it more clear in my code that I was overriding
something.

Also it looks like the @OutputCache approach could be used instead of this.
However my approach seems a lot more flexible. For example with OutputCache
you can only specify that it expires in x seconds. In my situation I don't
want it to expire unless the underlying template.txt file changes. I can do
this easily with the Cache and overriding like I am doing, so I like this
custom approach. If you have any comments on this I'd appreciate hearing
about it.

Thank you Crow for all the great help!

Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top