Forum Widgets
Latest Discussions
Convert the standard Blazor navigation menu to a collapsible icon menu
While I admittedly love Blazor I’ve always changed the out-of-the-box navigation menu that comes with it. It’s the first manoeuvre I pull when spinning up a new Blazor app, stripping out the purple gradient and getting it in, what I consider, a “blank slate state”. The other change I’ve wanted to make to the out-the-box look is one of those deluxe collapsible menus that leave just the icons showing. Anyone that’s used Azure DevOps will know what I’m talking about. I’ve included a picture to show DevOps example of what I’d like to see in my Blazor app. It gives a load of extra screen real estate which is always a priority for me in business applications particularly with complex or intensive workflows. Plus it gives the user the option to remove the text prompts once they are familiar with the system which is supported with carefully selected icon choices. As with most tasks that I assume will be an obvious solution I hit my search engine of choice and looked to avoid reinventing the wheel. However I found no source of pre-written changes to achieve this and was directed to fairly expensive third party controls to solve this one for me, which, being tight fisted, pushed me to do it for myself. Here I hope you save you the trouble of paying a pretty penny or having to wrestle the CSS into submission and provide a guide for producing a nice collapsible icon navigation menu by altering the existing out of the box menu in Blazor. In the following example I have left all the standard styling as is with the menu and just done the changes required to make the collapsible menu. The three files that require changes are MainLayout.razor, NavMenu.razor and NavMenu.razor.css. The code changes are shown below: Firstly the NavMenu.razor requires a bool value (IconMenuActive) to indicate whether the icon menu is showing or not, then wrap the text of the each NavItem in an if statement dependent on this bool. Then a method for toggling this bool and EventCalBack to send a bool to the MainLayout.razor for shrinking the width of the sidebar. Lastly there needs to be the control for switching menu views (I used the standard io icon arrows). NavMenu.razor <div class="top-row ps-3 navbar navbar-dark"> <div class="container-fluid"> <span class="oi oi-monitor" style="color:white;" aria-hidden="true"></span> @if (!@IconMenuActive) { <a class="navbar-brand" href="">The Menu Title Here</a> } <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu"> <span class="navbar-toggler-icon"></span> </button> </div> </div> <div class="@NavMenuCssClass" @onclick="ToggleNavMenu"> <nav class="flex-column"> <div class="nav-item px-3"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="oi oi-home" aria-hidden="true"></span> @if (!@IconMenuActive) { <label>Home</label> } </NavLink> </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="counter"> <span class="oi oi-plus" aria-hidden="true"></span> @if (!@IconMenuActive) { <label>Counter</label> } </NavLink> </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="fetchdata"> <span class="oi oi-list-rich" aria-hidden="true"></span> @if (!@IconMenuActive) { <label>Fetch data</label> } </NavLink> </div> </nav> </div> <div class="bottom-row"> <div class="icon-menu-arrow"> @if (!@IconMenuActive) { <span class="oi oi-arrow-left" style="color: white;" @onclick="ToggleIconMenu"></span> } else { <span class="oi oi-arrow-right" style="color: white;" @onclick="ToggleIconMenu"></span> } </div> </div> @code { //bool to send to MainLayout for shrinking sidebar and showing/hide menu text private bool IconMenuActive { get; set; } = false; //EventCallback for sending bool to MainLayout [Parameter] public EventCallback<bool> ShowIconMenu { get; set; } private bool collapseNavMenu = true; private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; private void ToggleNavMenu() { collapseNavMenu = !collapseNavMenu; } //Method to toggle IconMenuActive bool and send bool via EventCallback private async Task ToggleIconMenu() { IconMenuActive = !IconMenuActive; await ShowIconMenu.InvokeAsync(IconMenuActive); } } Next I add in a bit of CSS in to NavMenu.razor.css to put the arrow for toggling the menu at the bottom of the sidebar and a media query to make sure it doesn't show up in mobile view. The CSS classes added are .bottom-row and .icon-menu-arrow. NavMenu.razor.css .navbar-toggler { background-color: rgba(255, 255, 255, 0.1); } .top-row { height: 3.5rem; background-color: rgba(0,0,0,0.4); } .bottom-row { position: absolute; bottom: 0; padding-bottom: 10px; text-align: right; width: 100%; padding-right: 28px; } .icon-menu-arrow { text-align: right; } .navbar-brand { font-size: 1.1rem; } .oi { width: 2rem; font-size: 1.1rem; vertical-align: text-top; top: -2px; } .nav-item { font-size: 0.9rem; padding-bottom: 0.5rem; } .nav-item:first-of-type { padding-top: 1rem; } .nav-item:last-of-type { padding-bottom: 1rem; } .nav-item ::deep a { color: #d7d7d7; border-radius: 4px; height: 3rem; display: flex; align-items: center; line-height: 3rem; } .nav-item ::deep a.active { background-color: rgba(255,255,255,0.25); color: white; } .nav-item ::deep a:hover { background-color: rgba(255,255,255,0.1); color: white; } @media (min-width: 641px) { .navbar-toggler { display: none; } .collapse { /* Never collapse the sidebar for wide screens */ display: block; } } @media (max-width: 640px) { .bottom-row { display: block; } } Finally I add in the handler for the EventCallback to MainLayout.razor and a method to alter the width of the sidebar. MainLayout.razor @inherits LayoutComponentBase <div class="page"> <div class="sidebar" style="@IconMenuCssClass"> <NavMenu ShowIconMenu="ToggleIconMenu"/> </div> <main> <div class="top-row px-4"> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> </div> <article class="content px-4"> @Body </article> </main> </div> @code{ private bool _iconMenuActive { get; set; } private string? IconMenuCssClass => _iconMenuActive ? "width: 80px;" : null; protected void ToggleIconMenu(bool iconMenuActive) { _iconMenuActive = iconMenuActive; } } The final product of these little changes are shown in the pictures below: I'd love to hear if anyone has tackled this in a different way to me and if they've got any ideas on making it cleaner. Have yourselves a wonderful day, GavGavin-WilliamsFeb 26, 2023Brass Contributor70KViews10likes14CommentsLooking for recommendations for hosting ASP.NET web apps
I've been with an ASP.NET web hosting service for several years. However, the service provided has declined in the last couple of years. So, I started looking for a new, inexpensive, web hosting service. This is for my side business, which doesn't attract that much traffic. Yes, I'm sure that Azure would do, but like I said I'm trying to keep costs down. Naturally, I started searching. I've come across a couple of "Top 10 hosting services for 2023". I've spent about three weeks looking at different ones. I want to publish my ASP.NET Core both from Visual Studio and Azure DevOps Services, using the Azure DevOps FTP task if necessary. My website is currently written in .NET 6. This search experience has not been a pleasant experience. Some services I've spoken to said that because I am working with ASP.NET, then it can only run on Windows, and therefore I couldn't use their service, since they are a Linux only provider (mostly WordPress). I have told two of these web hosting services that ASP.NET Core can run on Linux. I even shared links from Microsoft that ASP.NET Core can run on Linux, Mac, and Windows. In both cases their response was disbelief and a refusal to discuss the topic further with me. Since it seems that many web hosting services have a mindset that refuse to accept the idea that anything from Microsoft can run on Linux, I decided to go back to researching web hosting companies that offer ASP.NET on Windows (both traditional .NET Framework varieties as well as .NET Core with .NET 5, 6, and 7). I settled on one, but they insist that I must allow them to re-register the domain I've owned for 10+ years. They will not allow me to upload my website to them until I've unlocked my website from the domain registrar I use. I've told them, at least three times, that I am satisfied with the domain registrar I have and only need a web hosting provider. They won't hear of it and refuse to go any further with me. So, once again I'm back to searching for a web hosting company for small businesses, that is inexpensive (OK, cheap), that I might be able to have multiple domains on. Therefore, I'd appreciate recommendations from this community, please.Rod-FMay 24, 2023Iron Contributor1.3KViews0likes8CommentsMultiple tables in MVC application
Hello all, I am new to the ASP.NET Core and MVC development. My goal is to create a simple Movie Management Web Application, just like the one in this tutorial: https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-6.0&tabs=visual-studio I already followed this tutorial 2 times, to learn the concept. But there is something missing. I want to separate the Genre from Movie in my database. I must have two tables: Movie and Genre. They must be linked by the Foreign Key GenreID in the Movie table. As the above tutorial doesn't show me how to do it. I would like to get your help here. How do I generate the database properly from my models? PS: I already created two Models classes: Movie and Genre. After scaffolding, only one table was generated in the database: Movie. The Genre table was completely ignored. Thank youKonstantin_PankratovJul 18, 2022Copper Contributor2KViews0likes7CommentsMVC Controller Method Overloading
Hi Folks, The application is built using .NET Framework 4.5.2 with MVC pattern. The current situation requires validating the input parameter and redirecting to the respective method. public ActionResult GetSomeData() { // Default execution for given route } public ActionResult GetSomeData(int inputValue) { // Route detection with the input parameter and change the functional flow for INT data type } public ActionResult GetSomeData(string inputString) { // Route detection with the input parameter and change the functional flow for STRING data type } Is such redirection possible? Thank you for reading.DSK ChakravarthyNov 26, 2023Copper Contributor2.4KViews0likes6CommentsWhy is my ASP.Net Web API piling up memory?
Hi everyone, I have a very simple MVC web api with a single controller that currently does nothing but returning a value. I am publishing it in VS2022 Preview 1 into a single file, so I get an .exe as an output. So far so good. That all seems to work fine. I have a C++ application that is communicating with that Web API and is starting it in an own process. Basically my test is calling an endpoint of the API every 250ms and what I noticed is that this fills up my memory (slowly but constantly). Starting with 16MB, after an hour the processs has swallowed around 90MB of RAM. Can anybody please tell me why is that? I am lost. Here is the complete code of the Web API: // My Controller [ApiController] [Route("[controller]")] public class TestController : ControllerBase { // Calling this endpoint every 250ms from my C++ application via http [HttpGet("buttonstate")] public int GetButtonState([FromQuery] string path) { return 0; } } // My startup class public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } // My program public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }SolvedSamXionNov 12, 2021Copper Contributor2.6KViews0likes6CommentsBlazor WASM PWA – Applications updates, cache busting with notification or force refresh
My team is currently working on a Blazor application and after several bouts of confusion between developers and testers we stuck a version number on the home screen and discovered the updates weren’t going out to everyone as we were expecting. We ended up with several people on different versions of the application and fortunately we spotted this issue early in development. I’ve put together the options and info I’ve found while trying to find a solution to this that works for our particular situation in hopes that it will help someone else dealing with this and hopefully open a discussion on how people are handling this issue and find any alternative solutions. To look at what was happening behind the scenes, I set up a simple WASM PWA on .NET7 and have it hosted on an Azure App Service. I stuck a version number on the home page so I can easily see when the update has taken place. The behaviour: Blazor WASM PWA applications load the application into the browser based on the cache pulled in by the service workers (Javascript assets that act as a proxy between browsers and web servers for offline support and performance). In dev tools you can see what’s in the cache storage for the app (go to dev tools > application tab > cache storage). The picture below shows that the cache contains “blazor-resources” and “offline-cache”. The “offline-cache” is the important one that determines what the site is displaying and on pushing an update the “blazor-resources” is unaffected so for this purpose can be ignored. Now the standard behaviour on pushing an update to the app is that the service worker will install the new app cache in the background and enter the “waiting” state and will not activate the newly cached app until the current application service worker is released, by either closing the browser or hard refreshing the app (Ctrl + F5). This behaviour is by design to prevent having two tabs open with different versions of the application running at once. However users may never close the application or browser or whatever and that would mean they could be running long retired versions of your application for an indeterminant length of time. Below you can see the cache storage after an update has been pushed stacking up the old and new version of the offline-cache. Once the service worker has been released then the old cache is removed the latest will be activated. This will then display the new version of the app. The solution: Now, what if we want to change this behaviour to either prompt and update or force one? Either way we will want to remove the need to close browsers or hard refresh as that can be a bit of a tricky one to get end users to get on board with. The service workers actually have a method that can skip the “waiting” stage of the service worker lifecycle clear the old cache and activate the latest. This is the SkipWaiting method. In the Blazor solution there is the service-worker.published.js file found in the wwwroot folder. This file contains the methods for the service worker. In this file there is a OnInstall method and can be modified to the following adding in the SkipWaiting method: async function onInstall(event) { console.info('Service worker: Install'); self.skipWaiting(); // Fetch and cache all matching items from the assets manifest const assetsRequests = self.assetsManifest.assets .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url))) .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url))) .map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' })); await caches.open(cacheName).then(cache => cache.addAll(assetsRequests)); } This additional line will now allow a standard refresh to update the application rather than requiring a hard refresh or closing the browser completely. When looking at the cache storage when an update is pushed you will see the second cache appear then the old cache disappear immediately. Note: Adding this behaviour will overwrite the intended behaviour and allow the potential of different version of the application running in different tabs. However we can look at avoiding that by forcing update later. Next, regardless of whether we want to prompt the user for an update or force it on them, we need a way of letting the site know it needs an update. My javascript is less than brilliant so I’ve used a solution by Wouter Huysentruit, full description here: https://whuysentruit.medium.com/blazor-wasm-pwa-adding-a-new-update-available-notification-d9f65c4ad13 This involves adding a js file called sw-registrator.js to the wwwroot folder that will allow an event to be triggered that can link to updating the site: window.updateAvailable = new Promise((resolve, reject) => { if (!('serviceWorker' in navigator)) { const errorMessage = `This browser doesn't support service workers`; console.error(errorMessage); reject(errorMessage); return; } navigator.serviceWorker.register('/service-worker.js') .then(registration => { console.info(`Service worker registration successful (scope: ${registration.scope})`); registration.onupdatefound = () => { const installingServiceWorker = registration.installing; installingServiceWorker.onstatechange = () => { if (installingServiceWorker.state === 'installed') { resolve(!!navigator.serviceWorker.controller); } } }; }) .catch(error => { console.error('Service worker registration failed with error:', error); reject(error); }); }); window.registerForUpdateAvailableNotification = (caller, methodName) => { window.updateAvailable.then(isUpdateAvailable => { if (isUpdateAvailable) { caller.invokeMethodAsync(methodName).then(); } }); }; Within index.html in the wwwroot folder we will need to register this new file instead of the service-worker.js. So we need to replace the reference to service-worker.js with the following: <script src="sw-registrator.js"></script> This will now raise an event once the cache refresh happens that can be used to trigger a prompt on the application or a refresh of the application. Now we need a razor component that will listen for the event and either throw up a refresh prompt or just force a refresh. Firstly I’ll do the prompt. For this make a new razor component and add the following code: @inject IJSRuntime _jsRuntime @inject NavigationManager uriHelper @if (_newVersionAvailable) { <button type="button" class="btn btn-danger shadow floating-update-button" onclick="window.location.reload()"> A new version of the application is available. Click here to upgrade. </button> } @code { private bool _newVersionAvailable = false; protected override async Task OnInitializedAsync() { await RegisterForUpdateAvailableNotification(); } private async Task RegisterForUpdateAvailableNotification() { await _jsRuntime.InvokeAsync<object>( identifier: "registerForUpdateAvailableNotification", DotNetObjectReference.Create(this), nameof(OnUpdateAvailable)); } [JSInvokable(nameof(OnUpdateAvailable))] public Task OnUpdateAvailable() { _newVersionAvailable = true; StateHasChanged(); return Task.CompletedTask; } } I personally like a red bar across the top as it’s very attention grabbing so you can add the following css file called WhateverYouCalledTheComponent.razor.css: .floating-update-button { position: relative; top: 0; padding: 1rem 1.5rem; width: 100%; } This component can then be placed at the top of MainLayout.razor above the body to ensure it appears anywhere on the app the user happens to be. This will then produce the following result once an update is pushed out: Once the banner is clicked, it will reload the site and the new update will be running. This is the setup that I will be implementing on my teams project as I wouldn’t want the site to force updates in case a user was in the middle of data entry. However if a forced refresh is desired, it’s a quick change to the razor component to allow that. Change the components code to the following: @inject IJSRuntime _jsRuntime @inject NavigationManager uriHelper @code { protected override async Task OnInitializedAsync() { await RegisterForUpdateAvailableNotification(); } private async Task RegisterForUpdateAvailableNotification() { await _jsRuntime.InvokeAsync<object>( identifier: "registerForUpdateAvailableNotification", DotNetObjectReference.Create(this), nameof(OnUpdateAvailable)); } [JSInvokable(nameof(OnUpdateAvailable))] public Task OnUpdateAvailable() { uriHelper.NavigateTo(uriHelper.Uri, forceLoad: true); StateHasChanged(); return Task.CompletedTask; } } Now on pushing an update you will see that the update is installed in the cache and once the event is triggered the old cache is removed and the site reloads wherever it happens to be. I’d be really interested to hear other peoples takes on this or if they’ve found other methods of achieving this, I’ve scoured the web and this was the combination of the best methods I came across but certainly open to improvement.Gavin-WilliamsSep 07, 2023Brass Contributor12KViews0likes5CommentsPropertyNames migration error from .NET Framework to .NET 6
Does anyone know how to fix this code to get it to work for .NET 6? I have researched the MS website documentation and I'm still unsure how to proceed. In the code below, the error occurs on the PropertyNames word. I've left out some code for brevity but I hope there is enough code posted to help you understand what I'm trying to accomplish. var modifiedEntities = ChangeTracker.Entries().Where(p => p.State == EntityState.Modified).ToList(); foreach (var change in modifiedEntities) { var entityName = change.Entity.GetType().BaseType.Name; var primaryKey = GetPrimaryKeyValue(change); foreach (var prop in change.OriginalValues.PropertyNames) //ERROR occurs on PropertyNames on this line. { //code that writes the OldValue and NewValue to ChangeLog database table is here } }mlightsoutJul 25, 2023Copper Contributor1KViews0likes5CommentsASP.Net Core 6 Web App - Fails to connect to database after published to on-prem IIS
Dear Community, I started to learn .Net core and entity framework, and its great. I built a small webapp as a test with a database (SQL LocalDB) and locally on my dev machine, it works fine. I publish to a folder location, then copy locally to a Windows 2019 Server and added a website on the server's IIS. The app will run the razor pages without a model, but the page that serves the model to add data or view data from the SQL database fails and the error is weird and it says there is no server found and cannot authenticate NT Authority\System. I made sure that SQL server express is installed and I can connect, I made sure localDB was added as a feature to the sqlexpress instance, etc., etc., My question is, do I have to do anything funky like wear a foil paper hat, to get this to work? I cant seem to find any documentation at all and youtube tutorials go through all the motions except publishing the app. Any help will be greatly appreciated.Hugo O. OrnelasApr 18, 2023Copper Contributor5.8KViews1like5CommentsUnable to get text value from user prompt
I hope someone can help point me in the right direction. I'm a newbie and have inherited a legacy application and no other employees can help me with this one. I have an asp.net application that has a Copy button. When the copy button is pressed, a screen pops-up and users can enter a value to indicate what they want to copy to. However, the copy does not work. I can not seem to get the text that the user enters to be picked up in the code so the copy can work. Why am I unable to get the code to pick up the text that is entered by the user? I have attached the files and a screenshot showing the copy button feature. I'd appreciate any guidance/help on this. As mentioned, I'm a newbie when it comes to this. Thanks.kemppaikMar 30, 2023Copper Contributor1.7KViews0likes5CommentsSession values lost on switching server with statesession in asp.net webform with webfarm blue/green
Hi, I have an asp.net webform website implementing blue/green architecture to get smooth deployment. The blue/green is a webfarm using ARR in IIS 10 and the website use ASP.NET State Service. The site blue and green are on the same server (same IIS) as the ASP.NET State Service. The web.config contains the correct configuration to get the webfarm work correctly <sessionState mode="StateServer" stateConnectionString="tcpip=loopback:42424" cookieless="false" timeout="20"/> MachineKey and validationkey identical When we swap the blue/green website, the user can smoothly continue his navigation on the website (same sessionid used by the user on both website each time we swap). However, the values in the session do not follow up. They seem to be compartmentalised by each website. I finally found a possible explanation stating that in a webfarm, the website should have the same ID so the session values follow. Load-Balanced IIS 7.5 Web Server ASP.NET Session State problem - Server Fault My problem is that I can't have the 2 websites having the same ID because they are in the same IIS (same server). Is there any workaround or setting I can change to correct that behaviour? Thank you,JfFerlandMar 29, 2023Copper Contributor1.6KViews0likes5Comments
Resources
Tags
- ASP.NET Core148 Topics
- ASP.NET (Classic)79 Topics
- Web API61 Topics
- Blazor60 Topics
- mvc53 Topics
- Razor Pages35 Topics
- IIS.NET27 Topics
- security26 Topics
- SignalR5 Topics
- community1 Topic