Keeping state of component after refresh - c#

Hello i am wondering how can you keep state of a component variable in Blazor without using different pages.
Lets say i have a Parent page that has a Login component :
Login
#functions()
{
public Action<string>onlogin{get;set;} //some logic that triggers this event to the parent , ---not important
}
Main
#if(this.id==string.Empty)
{
<Login onlogin="#((value)=>OnLoginEvent(value))"></Login>
}
#functions()
{
public string id{get;set;}=string.Empty;
public void OnLoginEvent(string value)
{
this.id=value;
}
Now as you can see ,the first time i render the Main component and i log in , the id will become be different from string.Empty, and so the Login component will then disappear.
However if i refresh the page , i am still back with the login component rendered ,so the id is resetted.
Can i somehow keep the state of a Component variable even after refresh ? In this case i want to keep id from being string.Empty even after refresh?
P.S I do not want to use different pages , and i was thinking as a solution to store the value of id in a service that is injected.Is there any other way?

A service would be a good way to solve your problem, as you've concluded. But another option would be to use the browsers local storage. This would persist your data in a very robust way. You can use a library such as this one BlazoredLocalStorage (Full disclosure, I'm the author).
This method would persist the data outside of a users session though, so, for example, a user could close the browser and come back a day later and the data would still be present. So you would have to manage that. But this is how many SPA applications handle this problem.

Related

ASP.NET MVC form wizard prevent user skipping wizard step (Controller Action) using URL bar

I’m currently working on a very large form. I thought it would be a good idea to section the form by implementing a form wizard (multiple views/action results) to improve the user experience.
One requirement is that the user must complete a small eligibility test that ensures they meet the minimum requirements prior to starting the application wizard itself.
Having done nothing like this before I can only see one approach to this problem and that is using a flag e.g IsEligible in a session that determines if the user can access the form wizard view/s. Let’s say my controller has two ActionResults (Eligibility and WizardStepOne) that server separate views. For example:
Controller - Untested Code
public ActionResult Eligibility()
{
Return View();
}
[HttpPost]
public ActionResult Eligibility(EligibilityViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
Session["IsEligible"] = true;
return("Success");
}
public ActionResult WizardStepOne()
{
bool stuff = (bool)Session["stuff"];
if(IsEligible == null)
{
return("Eligibility");
}
return RedirectToAction("Eligibility");
}
In short if the user attempts access the first step of the wizard and the IsEligible flag hasn't been set by the Eligibility post action then the user get redirected back to the eligibility form.
I've also looked into action filters but couldn't make much sense of it. I'll also have to implement this functionality at a later stage to prevent users skipping between wizard steps using the url e.g skipping WizardStepOne and starting at WizardStepTwo.
Is there a better approach then one described above in this situation? I'd rather avoid using a session as restarting the form becomes problematic as it would require a restart button to abandon the session especially between wizard steps.
What you are mentioning sounds like you might make use of some simple state machine to define valid steps through your form. So, when user is at stage 3. for example, you will check if he came from step 2 or not. For each step for particular user and session > you can save some hash value in his session. That way they could make no use typing in url directly.

Handling Session_Start in an Orchard CMS module

A little background:
We need to develop a custom Orchard module for a client that will catch the external URL referrer (if any) and store it in a session variable for later use, e.g. submitting a query for one of their products.
My naive solution was to suggest we record the URL referrer on Session_Start because it is a reliable way of knowing how the user got to our site. The problem is that the client does not want us touching the global.asax.cs file. It has to be done via a custom module. This is non-negotiable.
So my question is this: how can I reliably retrieve and store the UrlReferrer information when a new session starts using an Orchard module?
Or alternatively, is there some other way I can hook into the page lifecycle and maybe check whether or not the previous page was an external referrer?
My most important concern here is I need to know whether someone clicked on a sponsored link and I need to find that out in a module, not global.asax.cs. I am not dead set on any particular tracking method, as long as it is possible in the Orchard framework given the limitations imposed on me.
FYI: Orchard version is 1.8+
You can do this from a filter. I implemented this a while ago in my commerce module, to enable giving discounts or attributions for conversions from partner sites, typically. You can see the source code for my filter here: https://github.com/bleroy/Nwazet.Commerce/blob/master/Filters/ReferrerFilter.cs
What I would do, is create a custom module and in there a custom controller:
public class ReferrerController : Controller {
public ActionResult Index(string referrer) {
if (Session["Referrer"] != null) {
// do nothing, already used as entry point in the current session
} else {
// handle referrer, probably also some timestamp or hash
Session["Referrer"] = referrer; // save in session
}
return RedirectToRoute("~/"); // redirect to home
}
}
Obviously, also create a route for this. Then from the external referrers, go to this route where the referrers will be handled. (http://example.com/referrer?referrer=somereferrer)

How to Require SSL on a specific Page Type but not on the parent page

I'd like to know if Kentico has a "best practice" way to ensure the Requires SSL property is set as Yes on a specific Page Type, without inheriting the property from the Parent page.
I have researched this and have implemented a working solution (below) but am interested to know if there is a better "out of the box" solution that I may have overlooked.
We are using Kentico v8.2 with ASPX + Portal Page Types.
Our technical requirements
Serve the parent listing page over HTTP or HTTPS
Serve the child pages over HTTPS only
Our use case scenario
The user browses a page listing Job Vacancies. The user opens a specific Job Vacancy page which contains an Application Form. The user is confident entering personal details into the Application Form as the page is served over a secure connection.
Considered solutions
The closest "out of the box" solution I could find was to set the parent listing page to Require SSL = Yes and then inherit this on the child pages, however this doesn't meet our technical requirement to allow the listing page to be served over HTTP.
I also decided against manually setting Requires SSL = Yes on each child page as I didn't want to place this burden on the CMS Editors, give them more permissions than necessary and open it up to human error.
Current solution
So I ended up writing a Custom Event handler to set the Requires SSL property on Document Insert or Document Update events.
Initially I was doing this based on Page Type (Node.ClassName) but changed it to be based on a Field value so that I could more easily apply this to other Page Types by simply adding a field without refactoring my code and deploying a DLL.
[CustomEvents]
public partial class CMSModuleLoader
{
private class CustomEvents : CMSLoaderAttribute
{
public override void Init() {
DocumentEvents.Insert.Before += Document_Insert_Before;
DocumentEvents.Update.Before += Document_Update_Before;
}
void Document_Insert_Before(object sender, DocumentEventArgs e)
{
SetRequiresSSL(e.Node);
}
void Document_Update_Before(object sender, DocumentEventArgs e)
{
SetRequiresSSL(e.Node);
}
private void SetRequiresSSL(TreeNode node)
{
//if RequiresSecureConnection field is equal to true
if (node.GetBooleanValue("RequiresSecureConnection", false))
{
//if Requires SSL is not Yes
if (node.RequiresSSL != 1)
{
//set Requires SSL
node.RequiresSSL = 1;
}
}
}
}
}
Related urls
https://docs.kentico.com/display/K8/Configuring+SSL
https://docs.kentico.com/display/K8/Reference+-+Global+system+events
https://docs.kentico.com/display/K8/Handling+global+events
You can achieve out of the box without any customisation and still make it editable if you use the system attribute on the page type:
Open you page type
add a new field
select Field type : Page field
select Group : Node fields
select field name : RequiresSSL
enter a default value : 1 (which is YES for this type)
Deselect the Display field in editing form so the editor wont see it.
This way all pages created based on this page type will have the RequiresSSL preselected. And it's still adjustable.
David

Is it acceptable to store user specific data in C# Runtime MemoryCache?

In my asp.net MVC app, each page contains a lot of data that changes very rarely, but is still user specific and should never be shared among other users.
I couldn't find a server side solution that handled a cache per-user, so my idea is to just use the 'standard' memorycache and use the user-ID as part of the key.
Is this acceptable? Am I missing some security risks?
Thanks
EDIT: (added details)
It is data that is originally stored in the database, for example, I have a custom-made dropdown list (which is retrieved using AJAX and returns a jsonresult) for product-categories. I want to be able to manually clear the cache, in case the user adds a category via settings and I need the retrieve a 'new' category list. To my knowledge I cannot manually clear the cache with OutputCache. I also have a scenario where I want to refresh certain cache item every minute (for some updates on the user's screen).
Annotate your action with OutputCache and for consistency make sure the action is for authorized access only.
[Authorized, OutputCache(VaryByCustom = "USER")]
public ActionResult SlowAction() { }
Then in Global.asax.cs override the 'VaryByCustom' handler
public override string GetVaryByCustomString(HttpContext context, string custom)
{
switch (custom)
{
case "USER":
return context.User.Identity.Name;
default:
return null;
}
}

Keep partial form data when switching localization?

I used this great guide to localize my ASP.NET MVC 2 application, which I followed almost to the letter. The app is mainly form based.
I was wondering if there was an easy way to be able to switch between languages in the middle of filling out a form without clearing the whole form, and having to start over? If not, could you suggest a way of localizing an application that would support this?
Maybe that's not a thing...
The approach used in the article is not the best one to keep the localisation I guess.
But what you can do is the following:
Handle event when user clicks on the language link.
Change language via ajax preventing browser to go to the actual link.
Submit the form that user is editing adding parameter saying "make sure you don't save".
The server would re-render the form as normally with the data posted, but in the new language.
JavaScript pseudocode:
var submitCurrentForm = function() {
$("form:last").submit({
data { dontSave: "True"} // this is just meta, you can use QueryString or hidden input
});
}
var switchLanguage = function(href, done) {
$.post(href).success(done); // using jQuery deferred
}
$("a.lang").click(function(e) {
e.preventDefault();
switchLanguage(this.href, submitCurrentForm);
});
Controller pseudocode:
public ActionResult Create(YourStuff stuff, bool dontSave = false) {
if (!dontSave)
ProcessTheStuff();
return View(stuff);
}
Not the best solution, but the easiest one you can go with ATM.

Categories