Is there a way to check if page/frame in Windows 8 application exists in cache? Let's assume I have two pages: Home and Clients (navigation cache enabled). When I navigate to clients from home (by button) clients are loaded from database in OnNavigatedTo method. I navigate back to Home by Back button and than again to Clients. Now I see that clients are loaded from cache, which is good, but than again from OnNavigatedTo method. I'd like to load clients from database only once, when I open page for the first time. Later just load clients from cache.
How can I check than if clients were previously loaded or load them only on first page load? Maybe some other method?
Thank you!
Here's a solution to it ...
Sinche no one wants to load from cache in metro app so it's always better to reset the cache size for the respective frame. For pages where you want it to load from the cache. Just keep an if loop. and also check for the forwardStack in the History object.
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
if (e.NavigationMode == NavigationMode.Back)
{
ResetPageCache();
}
}
private void ResetPageCache()
{
var cacheSize = ((Frame) Parent).CacheSize;
((Frame) Parent).CacheSize = 0;
((Frame) Parent).CacheSize = cacheSize;
}
Here's a blog. Ill recommend you go through this first :)
BLOG
EDIT---------------------
Here are two links. Since i never faced the situation of loading the file from previous cache so I can share some findings :)
Here's the accesscache class
Access cache
and here's for winJS
winJS cache
the access cache might meet your requirement if you set caching to true for the pages you want :)
Ok, I solved my problem. Important is to have NavigationCacheMode enabled. In OnNavigatedTo method I just check whether list which to I saved data from database contains any elements. At first page opening it is empty so I load data from database to my list. Thus enabling NavigationCacheMode, data in variables are stored in cache, and loaded while navigating to this page. Some flags may be required.
Related
I'm developing a universal app using MVVM (light) and I'm trying to integrate OneDrive using the SDK. Each of my pages have a ViewModel associated with them.
I have a start up page (OneDrivePromptPage) where I offer the user to either sign in to Microsoft OneDrive or skip the sign in process.
When the user clicks on the Skip button, it calls the relevant command in my OneDrivePromptViewModel and navigates to my MainPage by calling:
this._navigationService.Navigate(typeof(MainPage));
The same applies when the user clicks on the Sign button and it prompts the user for their OneDrive credentials and if successfully logged in, it navigates to my 'MainPage'.
Now, here's my problem. When signs in successfully to OneDrive, I set a flag (IsSignedIn=true) to a container and save it to my storage (RoamingSettings).
All of the above works fine but I'm facing a problem where when I start the application again, it checks OneDrivePromptViewModel's constructor if the IsSignedIn value from the storage is set to true. If it is, I'll try to automatically sign in to OneDrive. If successful, I want to navigate to my 'MainPage' but this won't work.
It calls the same navigate code as above, doesn't throw any errors but it doesn't navigate to my 'MainPage' and ends up displaying my "Prompt" page.
public OneDrivePromptViewModel(INavigationService navigationService,
ISettingsDataService settingsDataService)
{
this._navigationService = navigationService;
this._settingsDataService = settingsDataService;
bool isSignedIn = false;
isSignedIn = this._settingsDataService.
GetItem<bool>("MyStoreApp", "IsSignedIn");
if (isSignedIn && !MyOneDrive.IsSignedIn())
{
ExecuteSignInCommand();
}
else if (isSignedIn && MyOneDrive.IsSignedIn())
{
NavigateToMainPage();
}
}
Any ideas why it's not navigating to the relevant page. Is it because I'm calling this from the constructor. If that's not the correct place to call it from, where should I call this from?
I'm not even sure, I should be loading the OneDrivePromptPage? Should I be performing this checks in a method of some sort before loading either OneDrivePromptPage or MainPage and perform the same checks mentioned above, but where do I put this method? In my App.cs?
Thanks.
In a recent Universal app I check for something similar, but initiate this in the OnLaunched event of the App.xaml.cs
Making sure based on the isSignedIn check that I navigate to the correct page like so:
bool navigated = rootFrame.Navigate(isSignedIn ? typeof(MainPage) : typeof(PromptPage);
You could try to see if this also works in your scenario
I have one url (/settings) that needs to point to two different pages depending on the users security on login. One page is the existing webforms page the other is a new MVC page. Is this even possible?
Additional Info:
When the user is on either page the url needs to say website.com/settings
Solution:
Convinced the PM to change the requirements.
The short answer, yes. You can do this several ways.
Javascript
Model View Controller (Controller)
ASP.NET Web-Forms (Method)
It is often poor practice to do such an event, as it can expose data. It is indeed possible:
Javascript:
$(document).ready(function () {
if($("#Account").val() != '') {
$(".Url").attr('href', 'http://www.google.com');
}
});
Pretend #Account is a hidden field that is populated from your database. If the field is not null then modify the .Url element to navigate to link. That approach for Web-Forms is the most simple.
Web-Forms:
protected void btnAccount_Click(object sender, EventArgs e)
{
if(User.IsInRole("Account"))
Response.Redirect("~/Admin.aspx");
else
Response.Redirect("~/User.aspx");
}
That would use the default Windows Authentication for the domain, you could bend and contort to use the database to pull data. An example, the Model View Controller would be similar as the Controller will simply handle that capability.
Hope this points in right direction.
This is a redirects based approach. Create a web page mapped to /settings, and have this code run on page load.
if(User.IsAdministrator()) //I take it you have some way of determining who is an Admin, so this is just example code
{
Response.Redirect("~/AdminSettings.aspx");
}
else
{
Response.Redirect("~/UserSettings.aspx");
}
Note that you'll need security on the Admin page to make sure a regular user can't just navigate directly there.
I have a question regarding the scope of a class that I created in relation to a web application.
My class is CCourseInfo and I create it as a private member of one of my web pages Enrollment.
In the Page_Load method, there is a database call to load the table data in the class member, DataTable. This DataTable is bound to a gridview.
This is the code:
public partial class Enrollment : System.Web.UI.Page
{
private Course CCourseInfo = new Course("Courses");
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
//Get the Environment Setting to determine the database to access
txtBoxEnvironment.Text = CurrentEnvironment;
DAL.setCurrentEnvironment(CurrentEnvironment);
//Get Course information from database
CCourseInfo.getData();
CourseGridView.DataSource = CCourseInfo.TableInfo;
CourseGridView.DataBind();
}
}
}
I want to implement Paging.
This method works but I have to get the data again to populate the DataTable in the CCourseInfo class.
protected void CourseGridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
CourseGridView.PageIndex = e.NewPageIndex;
CCourseInfo.getData();
CourseGridView.DataSource = CCourseInfo.TableInfo;
CourseGridView.DataBind();
}
My question is: Why do I have to get the data again? I set the DataTable in the Page_Load method and declared the class under the Enrollment class. Shouldn't the data still exists in the DataTable? How can I change my design so that I only have to get the data once?
Thanks,
You have to get the data again because ASP.NET (and in general, web pages) are stateless objects - this means that after each execution of your page, the page is cleaned up and all of its state is deleted. You'll have to recreate all of it when a new request comes in for the same page - the same page class will be instantiated again and you'll go through the page life cycle once more from beginning to end.
If you're not familiar with the page life cycle, here's an SO question / answers with quite a bit of detail - this will help you understand better what's going on during a request.
There are some things you can try (not an exhaustive list):
Cache all your records from the database in a cache server or in session state. If you have a lot of records, this could use a lot of memory (for each user) since all pages are loaded at once - you don't hit your database every time to query data. Caching speeds things up quite a bit but you may showing outdated data to the user - another user may change the data. It's also fairly tricky to properly handle cached data (when to remove it, when to fetch a fresh copy, etc.)
You can query only records for a single page - this results in lower data traffic between the web server and the database. You also have to query data every time the page changes, since you don't have more than the current page.
You can query all data and then send it to the client side and perform all paging in the browser. This generates a lot of traffic, since you have to send all pages to the client, whether the user wants to look at them or not. Paging is much faster this way but the browser uses a lot of memory and getting the data to the client can take a long time, depending on network speed.
The best solution is to get as little data as you can get away with (one page for the grid) - if you have to re-query it, the database will send you as little as needed.
Ok first because Web is using HTTP which is a stateless protocol so that's why you loose a web page's state.
So you have to manage the state your self. there are many ways that you can use to manage state.
Here is how i solved this problem i saved the data that i received from database and stored the entire list in View-state. And every time there is a post-back i retrieve the data from view-state.
if (!Page.IsPostBack)
{
ViewState["data"] = MyDataset;
DataListView.DataSource = ViewState["data"];
DataListView.DataBind();
}
if (Page.IsPostBack)
{
DataListView.DataSource = ViewState["data"];
DataListView.DataBind();
}
you can also use Session state and a few other state management techniques.
How can I clear browser cache only on logout, sure I can use the below:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(DateTime.UtcNow.AddHours(-1));
Response.Cache.SetNoStore();
But this particular page which is a shopping bag page is accessible by both login and non-login users. How can I set it in such a way whereby the login user is able to access this page without clearing the browser cache but Only clears it when he/she logs out so that another user will not be able to access the history contents.
I have tried the solutions here:
http://www.codeproject.com/Tips/135121/Browser-back-button-issue-after-logout
made some changes but still couldn't figure out how to deal with this issue.
I also cleared my session on logout as below but I understand the browser cache will still stay.
FormsAuthentication.SignOut();
Session.Abandon();
Response.Redirect("~/");
Please advice. Thanks.
I am not a c# expert, but I am pretty sure what you have above only tells the browser to not cache the page you are on. There is no way to tell the browser to clear cache on any page. This would be a problem if there was such a way. Sounds like the solution you need is to not cache any page at all, regardless of logging out or not.
Perhaps you are getting muddled with the difference between server and client cache?
If you set output cache on your aspx page, that's server-side cache, and you have a scenario where .NET can decide whether to send pre-cached content or not, and still apply ACL rules.
If you set cache requirements on the HTTP you return using Response.Cache, that's client-side caching. Once the browser obeys the cache rules you send here, the only opportunity you will have to retract your cache rules is the next time the browser requests the page. If you set the cache to expire tomorrow, that's the next chance you'll get to amend the caching. Assuming the browser is obeying you, by the way, of which there is no guarantee.
In short, dynamic pages should not attempt to set client-side caching if you want them to stay dynamic. In fact you should actively use techniques such as the ones you mentioned to suppress Caching on those pages at all times.
Client-side caching should really only be used to assist with performance and bandwidth on the static parts of your site.
I am trying to solve a similar problem myself. This is just speculation, but if i could track a user specific header in my requests I was going to try using
HttpContext.Current.Response.Cache.VaryByHeaders["login"] = true;
in the global.asax
public override string GetVaryByCustomString(HttpContext context, string arg)
{
if (arg == "login")
{
return User().Name;
}
return base.GetVaryByCustomString(context, arg);
}
There is a way to do it. If you are caching a page, you can add a vary parameter. For Example
[OutputCache(Duration = 60, Location = System.Web.UI.OutputCacheLocation.Client, VaryByParam = "random")]
[CompressFilter]
public ActionResult Page(PageModel model)
{
...
}
In the example above, if I pass a random variable like the ticks of the current datetime object, that will prevent the cache.
Monitoring my global exception logs this error seems to be impossible to remove no matter what I do, I thought I finally got rid of it but it's back again. You can see a strack trace of the error on a similar post here.
Notes about the environment:
IIS 6.0, .NET 3.5 SP1 single server ASP.NET application
Steps already taken:
<system.web>
<machineKey validationKey="big encryption key"
decryptionKey="big decryption key"
validation="SHA1" decryption="AES" />
In my Page Base for all of my pages
protected override void OnInit(EventArgs e)
{
const string viewStateKey = "big key value";
Page.ViewStateUserKey = viewStateKey;
}
Also in the source of the page I can see that all of the ASP.NET generated hidden fields are correctly at the top of the page.
First of all lets start from the fact, that this error of view state happens on PostBack.
Also I must say that I have done all the things that every one suggest to do to avoid this problem. And I have single machine, but 2 pools that run the same Pages.
So someone do an action, ether a man, ether some other search machine by 'clicking' on your pages, or some hacker try to check your system for problems...
I have similar problems (rare but existing ones), and I finally found that people try to hack-test my pages. (from the same IP I have and dos attacks)
I modify the function LoadPageStateFromPersistenceMedium() that translate the viewstate, and see by logging what exactly was the input, and from what IPs... then I started monitor these results and see that the view state was changed by hand - or was totally empty.
On error I just redirect him to the same page...
Here is what I did...
public abstract class BasePage : System.Web.UI.Page
{
protected override object LoadPageStateFromPersistenceMedium()
{
try
{
.. return the base, or make here your decompress, or what ever...
return base.LoadPageStateFromPersistenceMedium();
}
catch (Exception x)
{
string vsString = Request.Form[__VIEWSTATE];
string cThePage = Request.RawUrl;
...log the x.ToString() error...
...log the vsString...
...log the ip coming from...
...log the cThePage...
// check by your self for local errors
Debug.Fail("Fail to load view state ! Reason:" + x.ToString());
}
// if reach here, then have fail, so I reload the page - maybe here you
// can place somthing like ?rnd=RandomNumber&ErrorId=1 and show a message
Responce.Redirect(Request.RawUrl, true);
// the return is not used after the redirect
return string.Empty;
}
}
Second Reason
Now there is one more reason why this can happen, and the reason is because some one click on your page before the __EVENTVALIDATION is loaded.
This eventValidation is placed on the last button-even that asp.net found, and if you have some of them on many place on the page, or near the button, then this go to the end of the page.
So even if you see the viewstate on the top of the page, where is the Validation ??? maybe this never loaded - page corrupt ?, too fast user click on page ?
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" ... >
To avoid this kind of problem I made a simple javascript that I do not let it press the button unless this input have been loaded !!!.
One more comment, the __EVENTVALIDATION is not always presents ! so is maybe safer not to search for this field if you make a general solution, but to make a javascript trick to just check if the full page is loaded, or something else that you think.
Here is my final solution with jQuery: (note that I check on PageLoad if eventvalidation exist !). I have this placed on my MasterPages.
<script language="javascript" type="text/javascript">
function AllowFormToRun()
{
var MyEventValidation = $("#__EVENTVALIDATION");
if(MyEventValidation.length == 0 || MyEventValidation.val() == ""){
alert("Please wait for the page to fully loaded.");
return false;
}
return true;
}
</script>
protected void Page_Load(object sender, EventArgs e)
{
// I do not know if Page can be null - just in case I place it.
if (Page != null && Page.EnableEventValidation)
{
Form.Attributes["onsubmit"] = "return AllowFormToRun();";
}
}
You can test by placing near the button of your page a delay.
<% System.Threading.Thread.Sleep(5000); %>
Update
Today I see in log this message again for WebResource and what I discover is that a bot getting the pages and make all the character on the links in lower case, including the parameters, so this was one more reason to not getting the correct encoded string, and throw a message like Padding is invalid and cannot be removed.
Hope this help you more.
A survey of the web pages found with several of the keywords from the error message indicate that this type of error is relatively common, usually random (at least in appearance) and unfortunately rarely inclusive of an explicit work-around or explanation...
The existence of many similar-yet-different situations is probably tied to the very many different architectures and underlying configurations which can somehow lead to the inability of the crypto layer to assert the authenticity of the MAC (Message Authentication Codes) in the request pages:
Server farm setup
Cross domain / syndicated pages
third party widget libraries and such
Actual ASP program logic (of course)
One relatively frequent "marker" around these bug reports is the mention of resource requests (eg. WebResource.axd).
Note that such requests are often not logged (lest they inflate the log files size with event of relative little interest). This absence from the log file and the fact they are often cached (and hence the relative random and infrequent occurrence of the bug) may explain how this possible origin of the bug go "under the radar". This also suggests that in trying to recreate the bug, (while tracking in the logs, in real time etc) it may be useful to prevent the web browser from caching (or for the least to clear it cache initially).
In short, here are a few ideas and things to look for:
start logging the *.axd requests
try and co-relate such axd requests with the error events in the exception log
look for pages with resource references
if in a Farm setting, ensure that all instances use the same key (apparently the snippet provided in the question hint at multiple IIS servers)
Be suspicious of pages with 3rd party tie-ins (search services, affiliate programs...)
Hope this helps ;-)
Are you sure your problem is cryptography related, and not caused by oversized ViewState?
If ViewState is the problem, you can chunk it - change the value of pages / MaxPageStateFieldLength in web.config