Remove cache created with <cache> tag helper - asp.net

I have used <cache> tag helper in my Asp.Net Core 3.1 website to cache some parts of the page. However, in some situations I want to clear these cache entries and make the website re-create those. How can I achieve that? I tried the code mentioned in this answer but couldn't get it to work. When I register the service the application seems to ignore it and no entries get cached in my custom service.

Here is a way to do it:
private readonly CacheTagHelperMemoryCacheFactory factory;
public MyClass(CacheTagHelperMemoryCacheFactory factory)
{
this.factory = factory;
}
and later
(this.factory.Cache as MemoryCache).Compact(1.0);

Related

How to pass an object from one page component to another page component in a .NET Blazor app?

I have a .NET Blazor Server app and need to pass an object from one component to another. Both components are pages, meaning that they have #page directives with routes. I know how to use cascading values to pass a parameter between regular Blazor components, but this does not work with page components. I also know how to pass a parameter within an endpoint route. However, instead of a string or int I want to pass an object with multiple properties and am unsure how to best accomplish this.
Is it possible to pass an object as an endpoint route parameter? If not, what is a good way to accomplish this within a Razor components context?
Using dependency injection would likely solve this issue for you.
Example:
Create a class called "ApplicationService"
Create an interface in that class called "IApplicationService"
You could have something like this
public interface IApplicationService
{
public Task MsgBox(string value);
}
In the ApplicationService class inside the "ApplicationService.cs" file, go ahead and implement the interface member above.
You could have something like this:
public async Task MsgBox(string value)
{
await _JSRuntime.InvokeAsync<string>("alert", value);
}
In the program.cs class, you need to now register that "service" we just created.
You could have something like this
builder.Services.AddTransient<IApplicationService, ApplicationService>();
builder.Services.AddScoped<ApplicationService>();
In your _Imports.razor you can inject the class so that the pages have access to it:
#inject ApplicationService MainAppService;
Now in your razor components you should be able to do something like this:
await MainAppService.MsgBox("This is a message box");
This works in my WASM blazor app, hope it sheds some light on the server side of things 🚀
Use a DI service. Create a class to hold your object. Add it as a Scoped Service in Program. Use it in any component (pages are just components with a page attribute) though #inject.

How do I run code at client start (Not at page open) in Blazor

I need to run some code to get a user's username and department when they first connect to my Blazor Server Side application. I could just do this using OnInitialized() but that appears to only work on the one page in which it was placed. Users will likely be sent separate links to different pages though and I don't want to have to place this code on every page. I discovered that I can place code in my main layout and it will run no matter what page I start on but it runs on every page change and it doesn't allow me to run things asynchronously so that's not ideal. I'm looking for something like a Global.asax but in Blazor if that makes sense.
Edit: Turns out I can run things asynchronously in my layout! I just needed to create a code block like any other razor page. Makes sense. Though It's still weird that we have to put this type of code in the layout. It just doesn't feel right.
This is what I do:
Create a state object (class) that can be injected where needed. This is somewhat like session, but can also have global events. See here.
Add it to IoC in Startup.cs. Background info here
services.AddScoped<MyState>();
Initialize it in MainLayout.razor or elsewhere:
if (MyState.User == null)
{
MyState.User = authService.User;
}
Instantiate in pages/components as needed:
[Inject]
public MyState myState { get; set; }
...
myObj.CreatedBy = myState.User.UserName;

is reading web.config from a class insecure?

i wanted a way of getting settings without having to look them up every time so i made this simple class. ex:
public class CustomConfigSettings
{
public CustomConfigSettings()
{
// Default constructor.
}
public string MySetting
{
get { return ConfigurationManager.AppSettings["mySetting"]; }
}
}
it works fine, but it feels like it might be insecure (for some reason i can't put my finger on). would appreciate feedback on security issues, if any, and any possible alternatives. (webforms; .net 3.5).
This is not insecure by itself. Security depends on who will access your class and if this class permits changes to configurations, then if somebody access your code, he can change settings.
I don't see any reason it would be considered more or less secure to read AppSettings from a class than to read them directly from your code. You're using the proper calls and syntax.
There is no problem with your code.
Anyway you can make the function static, it will look better and do not require creating new instance.

Managing page paths in ASP .NET application

Currently in my web application I have plenty of lines like this:
Response.Redirect("~/Default.aspx");
etc. Now, I'm in the process of reorganizing aspx pages structure, as it's pretty flat - everything is in one folder. So I have to thoroughly search all the code in order to fix aspx paths. So my question is: is there any way to manage/organize web site pages structure in ASP .NET - some kind of SiteMap, so that I have a code similar to:
Response.Redirect(Pages.Default);
so that my code will be closed for modifications where some aspx pages are moved between folders?
I've written an open source project that will help you, http://navigation.codeplex.com/.
You list your pages and transitions in a config file. Here's an example:
<state key="Page1" page="~/Page1.aspx">
<transition key="Next" to="Page2"/>
</state>
<state key="Page2" page="~/Page2.aspx"/>
Then in your code you can move from Page1.aspx to Page2.aspx like this:
StateController.Navigate("Next");
Let me know if you're interested or need any help.
I don't think there there's any automatic solution, you'll probably end up building something yourself. You may want to check out the Asp.Net Sitemap stuff, although it's mainly focused on Navigation controls.
http://msdn.microsoft.com/en-us/library/yy2ykkab.aspx
I ran into the same issue you're facing on a few projects. One simple solution is to create constant/static/enums to represent the page names/urls:
public static class SiteMap {
public static readonly string Default = "/default.aspx";
}
which of course lets you do
Response.Redirect(SiteMap.Default);
But that was outgrown quickly as the pages required parameters passed in, and sooner or later you run into exactly the same problem with the parameter names. So we expanded on that idea by adding an Url factory class like
public static class SiteMap {
public static readonly string Article = "/blog/article.aspx";
}
public static class PageParams {
public static readonly string ArticleId = "aid";
}
public static class UrlFactory {
public static string GetUrlBlogArticle(int articleId){
return string.Format("/{0}?{1}={2}",SiteMap.Article, PageParams.ArticleId, articleId.ToString());
}
}
That approach ensures all the links work the same way and include the same parameters. By setting up a PageParams constants class the landing pages/controls code are a little cleaner too, since you can do
public void method(){
var articleId = Request[PageParams.ArticleId];
}
rather than have random request parameter names everywhere.
Hope that gives you some ideas.

Invalidate browser cache

I have a question related to cache invalidation techniques... I am trying to implement a mechanism for my website, that automatically invalidates browser cache (css, images...). I want to be able to programatically invalidate browser cache, whenever I update the website (change images or styles);
For example: for the current release, among others, the css and some of the images have changed. In this situation I want that after the update is finished, when a user performs a request to the website, his browser's cache to get automatically invalidated, thus forcing the re-download of the new images and styles. This should be done only for the client's first request... the following ones should be retrieved from cache (so setting the no-cache pragma is out of the question).
Here's what i've tried:
in the BeginRequest event handler, I added the following lines:
Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
Response.Cache.SetETag("\"e111293b17594f1487d136ea7e9314ac\"");
this sets the ETag in the response headers. I figured that if I change this ETag at each release, and set it at each request, the cache will be invalidated, but it seems that it is not. I used Live HTTP headers to see the results and the ETAG is correctly set up for the response, but the css and images are still taken from cache.
Any ideas of how I could accomplish this, or if it can be accomplished at all?
I have run into issues like this in the past. Unfortunately I couldn't find a really nice way to accomplish this so I had to come up with a workaround. I was only dealing with this issue for CSS files so I added an extra querystring parameter to every CSS reference, for example
<link rel="stylesheet" type="text/css"
href="default.css?buildnumber=<%= Buildnumber %>" />
The build number gets incremented with each release so the browser was forced to go look for this new file. Not an ideal solution, but it worked without a hitch.
For those who are seeking for a MVC5 solution:
Step1: Change the AssemblyInfo.cs file of the project to the following
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("1.0.*")]
Step 2: Create a class to get the current version info on your project:
public class Versioner
{
public static Version GetVersion()
{
Assembly thisAssem = typeof(Versionador).Assembly;
AssemblyName thisAssemName = thisAssem.GetName();
Version vrs = thisAssemName.Version;
return vrs;
}
//Not really necessary, just if you need to show this info
public static string GetDataBuild()
{
Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
DateTime buildDate = new DateTime(2000, 1, 1).AddDays(version.Build).AddSeconds(version.Revision * 2);
string displayableVersion = $"{version} ({buildDate})";
return displayableVersion;
}
}
Step 3: Call the class methods in the views which needs cache auto-refresh on new builds.
#{
Version _ver = <MyProject>.Classes.Extensions.Versioner.GetVersion();
}
//here, <MyProject>.Classes.Extensions is my path to the Versioner.cls class file, adjust it to your project's classes path
Step 4: Use the variable with the version string to append to your scripts or .css files
<script src="~/js/index.js?v=#_ver"></script>
<link href="/css/style.css?v=#_ver" rel="stylesheet" />

Resources